Added some new files for spandsp

This commit is contained in:
Steve Underwood 2010-07-25 03:43:53 +08:00
parent f029f7ef7c
commit ccbee25641
18 changed files with 3171 additions and 0 deletions

View File

@ -0,0 +1,96 @@
<?xml version="1.0"?>
<!DOCTYPE fax-tests SYSTEM "./fax-tests.dtd">
<fax-tests>
<config>
<path type="IMAGE" value="../test-data/etsi/fax"/>
</config>
<messages>
<!-- TCF = 2700 bytes at 14400, 2250 at 12000, 1800 at 9600, 1350 at 7200, 900 at 4800 or 450 at 2400 -->
<!-- Bad TCF == 10101010.... -->
<!-- slow HDLC preamble == 37 flag bytes -->
<!-- slow HDLC inter-frame flag sequence == 1 flag byte -->
<!-- slow HDLC end flag sequence == 5 flag bytes -->
<!-- synchronisation sequence == 250ms of zeros. = 450 bytes at 14400, 375 at 12000, 300 at 9600, 225 at 7200, 150 at 4800 or 75 at 2400 -->
<!-- fast HDLC inter-frame flag sequence == 1 flag byte -->
<!-- fast HDLC end flag sequence == 10 flag bytes -->
<!-- STAIRSTEP image is 1728x1728 pixels. Its is about 15k, so an average of 68.2 bits per row. To
cook it as a 31k page requires a min_bits of 141. To cook it as a 63k page requires a min_bits of
286. To cook it as a 64k page requires a min_bits of 291 -->
</messages>
<test-group name="Supplementary">
<test name="PPS-MPS-lost-PPS">
<!-- Tester calls DUT and sends one 31k byte STAIRSTEP page and one 15k byte STAIRSTEP page. -->
<step type="CALL"/>
<!--<step dir="T" type="CNG"/>-->
<step dir="R" type="CED"/>
<step dir="R" type="HDLC" modem="V.21" tag="DIS" value="FF C8 01 ..." timeout="60000"/>
<step dir="R" type="SILENCE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="DCS" value="FF C8 41 00 50 1F 30"/>
<step dir="T" type="POSTAMBLE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="TCF" modem="V.27ter/4800" value="900"/>
<step dir="R" type="HDLC" modem="V.21" tag="CFR" value="FF C8 21"/>
<step dir="R" type="SILENCE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif" min_bits="141"/>
<step dir="T" type="POSTAMBLE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="PPS-NULL" value="FF C8 7D 00 00 00 08"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
<step dir="R" type="SILENCE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif"/>
<step dir="T" type="POSTAMBLE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 00 80 08"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
<step dir="R" type="SILENCE"/>
<!-- Repeat the last chunk, as though we missed the MCF -->
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
<step dir="T" type="PP" value="etsi_300_242_a4_stairstep.tif"/>
<step dir="T" type="POSTAMBLE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 00 80 08"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
<step dir="R" type="SILENCE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.27ter/4800"/>
<step dir="T" type="PP" value="etsi_300_242_a4_white.tif"/>
<step dir="T" type="POSTAMBLE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="PPS-MPS" value="FF C8 7D 72 80 00 08"/>
<step dir="T" type="POSTAMBLE"/>
<step dir="R" type="HDLC" modem="V.21" tag="MCF" value="FF C8 31"/>
<step dir="R" type="SILENCE"/>
<step type="WAIT" value="75"/>
<step dir="T" type="PREAMBLE" modem="V.21"/>
<step dir="T" type="HDLC" tag="DCN" value="FF C8 5F"/>
<step dir="T" type="POSTAMBLE"/>
</test>
</test-group>
</fax-tests>

View File

@ -0,0 +1,466 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* image_translate.c - Image translation routines for reworking colour
* and gray scale images to be bi-level images of an
* appropriate size to be FAX compatible.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <memory.h>
#include <string.h>
#if defined(HAVE_TGMATH_H)
#include <tgmath.h>
#endif
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#include "floating_fudge.h"
#include <tiffio.h>
#include <assert.h>
#include "spandsp/telephony.h"
#include "spandsp/fast_convert.h"
#include "spandsp/logging.h"
#include "spandsp/saturated.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#endif
#include "spandsp/t4_t6_decode.h"
#include "spandsp/t4_t6_encode.h"
#include "spandsp/image_translate.h"
#include "spandsp/private/logging.h"
#if defined(SPANDSP_SUPPORT_T85)
#include "spandsp/private/t81_t82_arith_coding.h"
#include "spandsp/private/t85.h"
#endif
#include "spandsp/private/t4_t6_decode.h"
#include "spandsp/private/t4_t6_encode.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/image_translate.h"
static int image_colour16_to_gray8_row(uint8_t mono[], uint16_t colour[], int pixels)
{
int i;
uint32_t gray;
for (i = 0; i < pixels; i++)
{
gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
mono[i] = saturateu8(gray >> 24);
}
return pixels;
}
/*- End of function --------------------------------------------------------*/
static int image_colour8_to_gray8_row(uint8_t mono[], uint8_t colour[], int pixels)
{
int i;
uint32_t gray;
for (i = 0; i < pixels; i++)
{
gray = colour[3*i]*19595 + colour[3*i + 1]*38469 + colour[3*i + 2]*7472;
mono[i] = saturateu8(gray >> 16);
}
return pixels;
}
/*- End of function --------------------------------------------------------*/
static int image_gray16_to_gray8_row(uint8_t mono[], uint16_t gray[], int pixels)
{
int i;
for (i = 0; i < pixels; i++)
mono[i] = gray[i] >> 8;
return pixels;
}
/*- End of function --------------------------------------------------------*/
static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[], size_t len)
{
int row_len;
row_len = (*s->row_read_handler)(s->row_read_user_data, buf, s->input_width*s->bytes_per_pixel);
if (row_len != s->input_width*s->bytes_per_pixel)
return 0;
/* Scrunch colour down to gray, and scrunch 16 bit pixels down to 8 bit pixels */
switch (s->input_format)
{
case IMAGE_TRANSLATE_FROM_GRAY_16:
image_gray16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
break;
case IMAGE_TRANSLATE_FROM_COLOUR_16:
image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width);
break;
case IMAGE_TRANSLATE_FROM_COLOUR_8:
image_colour8_to_gray8_row(buf, buf, s->input_width);
break;
}
return row_len;
}
/*- End of function --------------------------------------------------------*/
static int image_resize_row(image_translate_state_t *s, uint8_t buf[], size_t len)
{
int i;
int output_width;
int output_length;
int input_width;
int input_length;
double c1;
double c2;
double int_part;
int x;
#if defined(SPANDSP_USE_FIXED_POINT)
int frac_row;
int frac_col;
#else
double frac_row;
double frac_col;
#endif
int row_len;
int skip;
uint8_t *p;
if (s->raw_output_row < 0)
return 0;
output_width = s->output_width - 1;
output_length = s->output_length - 1;
input_width = s->input_width - 1;
input_length = s->input_length - 1;
skip = s->raw_output_row*input_length/output_length;
if (skip >= s->raw_input_row)
{
skip++;
while (skip >= s->raw_input_row)
{
if (s->raw_input_row >= s->input_length)
{
s->raw_output_row = -1;
break;
}
row_len = get_and_scrunch_row(s, s->raw_pixel_row[0], s->input_width*s->bytes_per_pixel);
if (row_len != s->input_width*s->bytes_per_pixel)
{
s->raw_output_row = -1;
return 0;
}
s->raw_input_row++;
p = s->raw_pixel_row[0];
s->raw_pixel_row[0] = s->raw_pixel_row[1];
s->raw_pixel_row[1] = p;
}
}
#if defined(SPANDSP_USE_FIXED_POINT)
frac_row = s->raw_output_row*input_length/output_length;
frac_row = s->raw_output_row*input_length - frac_row*output_length;
for (i = 0; i < output_width; i++)
{
x = i*input_width/output_width;
frac_col = x - x*output_width;
c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col;
c1 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col;
buf[i] = saturateu8(c1 + (c2 - c1)*frac_row);
}
#else
frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part);
for (i = 0; i < output_width; i++)
{
frac_col = modf((double) i*input_width/output_width, &int_part);
x = int_part;
c1 = s->raw_pixel_row[0][x] + (s->raw_pixel_row[0][x + 1] - s->raw_pixel_row[0][x])*frac_col;
c2 = s->raw_pixel_row[1][x] + (s->raw_pixel_row[1][x + 1] - s->raw_pixel_row[1][x])*frac_col;
buf[i] = saturateu8(c1 + (c2 - c1)*frac_row);
}
#endif
if (++s->raw_output_row >= s->output_length)
s->raw_output_row = -1;
return len;
}
/*- End of function --------------------------------------------------------*/
static __inline__ uint8_t find_closest_palette_color(int in)
{
return (in >= 128) ? 255 : 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len)
{
int x;
int y;
int i;
int j;
int limit;
int old_pixel;
int new_pixel;
int quant_error;
uint8_t *p;
uint8_t xx;
if (s->output_row < 0)
return 0;
y = s->output_row++;
/* This algorithm works over two rows, and outputs the earlier of the two. To
make this work:
- At row 0 we grab and scrunch two rows.
- From row 1 up to the last row we grab one new additional row each time.
- At the last row we dither and output, without getting an extra row in. */
for (i = (y == 0) ? 0 : 1; i < 2; i++)
{
p = s->pixel_row[0];
s->pixel_row[0] = s->pixel_row[1];
s->pixel_row[1] = p;
/* If this is the end of the image just ignore that there is now rubbish in pixel_row[1].
Mark that the end has occurred. This row will be properly output, and the next one
will fail, with the end of image condition (i.e. returning zero length) */
if (s->resize)
{
if (image_resize_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
s->output_row = -1;
}
else
{
if (get_and_scrunch_row(s, s->pixel_row[1], s->output_width*s->bytes_per_pixel) != s->output_width*s->bytes_per_pixel)
s->output_row = -1;
}
}
/* Apply Floyd-Steinberg dithering to the 8 bit pixels, using a bustrophodontic
scan, to reduce the grayscale image to pure black and white */
/* The first and last pixels in each row need special treatment, so we do not
step outside the row. */
if ((y & 1))
{
x = s->output_width - 1;
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16);
for ( ; x > 0; x--)
{
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16);
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16);
}
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (3*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
}
else
{
x = 0;
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16);
for ( ; x < s->output_width - 1; x++)
{
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16);
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16);
}
old_pixel = s->pixel_row[0][x];
new_pixel = find_closest_palette_color(old_pixel);
quant_error = old_pixel - new_pixel;
s->pixel_row[0][x + 0] = new_pixel;
s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (3*quant_error)/16);
s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16);
}
/* Now bit pack the pixel per byte row into a pixel per bit row. */
for (i = 0, x = 0; x < s->output_width; i++, x += 8)
{
xx = 0;
/* Allow for the possibility that the width is not a multiple of 8 */
limit = (8 <= s->output_width - x) ? 8 : (s->output_width - x);
for (j = 0; j < limit; j++)
{
if (s->pixel_row[0][x + j] <= 128)
xx |= (1 << (7 - j));
}
buf[i] = xx;
}
return i;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s)
{
return s->output_width;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s)
{
return s->output_length;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s,
int input_format,
int input_width,
int input_length,
int output_width,
t4_row_read_handler_t row_read_handler,
void *row_read_user_data)
{
int i;
if (s == NULL)
{
if ((s = (image_translate_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
s->input_format = input_format;
s->input_width = input_width;
s->input_length = input_length;
s->resize = (output_width > 0);
s->output_width = (s->resize) ? output_width : s->input_width;
s->output_length = (s->resize) ? s->input_length*s->output_width/s->input_width : s->input_length;
switch (s->input_format)
{
case IMAGE_TRANSLATE_FROM_GRAY_8:
s->bytes_per_pixel = 1;
break;
case IMAGE_TRANSLATE_FROM_GRAY_16:
s->bytes_per_pixel = 2;
break;
case IMAGE_TRANSLATE_FROM_COLOUR_8:
s->bytes_per_pixel = 3;
break;
case IMAGE_TRANSLATE_FROM_COLOUR_16:
s->bytes_per_pixel = 6;
break;
default:
s->bytes_per_pixel = 1;
break;
}
/* Allocate the two row buffers we need, using the space requirements we now have */
if (s->resize)
{
for (i = 0; i < 2; i++)
{
if ((s->raw_pixel_row[i] = (uint8_t *) malloc(s->input_width*s->bytes_per_pixel)) == NULL)
return NULL;
memset(s->raw_pixel_row[i], 0, s->input_width*s->bytes_per_pixel);
if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*sizeof(uint8_t))) == NULL)
return NULL;
memset(s->pixel_row[i], 0, s->output_width*sizeof(uint8_t));
}
}
else
{
for (i = 0; i < 2; i++)
{
if ((s->pixel_row[i] = (uint8_t *) malloc(s->output_width*s->bytes_per_pixel)) == NULL)
return NULL;
memset(s->pixel_row[i], 0, s->output_width*s->bytes_per_pixel);
}
}
s->row_read_handler = row_read_handler;
s->row_read_user_data = row_read_user_data;
s->raw_input_row = 0;
s->raw_output_row = 0;
s->output_row = 0;
return s;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s)
{
int i;
for (i = 0; i < 2; i++)
{
if (s->raw_pixel_row[i])
{
free(s->raw_pixel_row[i]);
s->raw_pixel_row[i] = NULL;
}
if (s->pixel_row[i])
{
free(s->pixel_row[i]);
s->pixel_row[i] = NULL;
}
}
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s)
{
int res;
res = image_translate_release(s);
free(s);
return res;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,108 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* image_translate.h - Image translation routines for reworking colour
* and gray scale images to be bi-level images of an
* appropriate size to be FAX compatible.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if !defined(_SPANDSP_IMAGE_TRANSLATE_H_)
#define _SPANDSP_IMAGE_TRANSLATE_H_
/*! \page image_translate_page Image translation
\section image_translate_page_sec_1 What does it do?
\section image_translate_page_sec_2 How does it work?
\section image_translate_page_sec_3 How do I use it?
*/
typedef struct image_translate_state_s image_translate_state_t;
enum
{
IMAGE_TRANSLATE_FROM_MONO = 1,
IMAGE_TRANSLATE_FROM_GRAY_8 = 2,
IMAGE_TRANSLATE_FROM_GRAY_16 = 3,
IMAGE_TRANSLATE_FROM_COLOUR_8 = 4,
IMAGE_TRANSLATE_FROM_COLOUR_16 = 5
};
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Get the next row of a translated image.
\param s The image translation context.
\return the length of the row buffer, in bytes */
SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], size_t len);
/*! \brief Get the width of the image being produced by an image translation context.
\param s The image translation context.
\return The width of the output image, in pixel. */
SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s);
/*! \brief Get the length of the image being produced by an image translation context.
\param s The image translation context.
\return The length of the output image, in pixel. */
SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s);
/*! \brief Initialise an image translation context for rescaling and squashing a gray scale
or colour image to a bi-level FAX type image.
\param s The image translation context.
\param input_format x
\param input_width The width of the source image, in pixels.
\param input_length The length of the source image, in pixels.
\param output_width The width of the output image, in pixels. The length of the output image
will be derived automatically from this and the source image dimension, to main the
geometry of the original image.
\param row_read_handler A callback routine used to pull rows of pixels from the source image
into the translation process.
\param row_read_user_data An opaque point passed to read_row_handler
\return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s,
int input_format,
int input_width,
int input_length,
int output_width,
t4_row_read_handler_t row_read_handler,
void *row_read_user_data);
/*! \brief Release the resources associated with an image translation context.
\param s The image translation context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s);
/*! \brief Free the resources associated with an image translation context.
\param s The image translation context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,52 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/image_translate.c - Image translation routines for reworking colour
* and gray scale images to be bi-level images of an
* appropriate size to be FAX compatible.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(_SPANDSP_PRIVATE_IMAGE_TRANSLATE_H_)
#define _SPANDSP_PRIVATE_IMAGE_TRANSLATE_H_
struct image_translate_state_s
{
int input_format;
int input_width;
int input_length;
int output_width;
int output_length;
int resize;
int bytes_per_pixel;
int raw_input_row;
int raw_output_row;
int output_row;
uint8_t *raw_pixel_row[2];
uint8_t *pixel_row[2];
t4_row_read_handler_t row_read_handler;
void *row_read_user_data;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,101 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/t4_t6_decode.h - definitions for T.4/T.6 fax decoding
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003, 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(_SPANDSP_PRIVATE_T4_T6_DECODE_H_)
#define _SPANDSP_PRIVATE_T4_T6_DECODE_H_
/*!
T.4 1D, T4 2D and T6 decompressor state.
*/
struct t4_t6_decode_state_s
{
/*! \brief The type of compression used between the FAX machines. */
//int encoding;
/*! \brief Width of the current page, in pixels. */
//int image_width;
/*! \brief Callback function to write a row of pixels to the image destination. */
t4_row_write_handler_t row_write_handler;
/*! \brief Opaque pointer passed to row_write_handler. */
void *row_write_user_data;
/*! \brief A pointer into the image buffer indicating where the last row begins */
int last_row_starts_at;
/*! \brief This variable is used to count the consecutive EOLS we have seen. If it
reaches six, this is the end of the image. It is initially set to -1 for
1D and 2D decoding, as an indicator that we must wait for the first EOL,
before decoding any image data. */
int consecutive_eols;
/*! \brief The reference or starting changing element on the coding line. At the
start of the coding line, a0 is set on an imaginary white changing element
situated just before the first element on the line. During the coding of
the coding line, the position of a0 is defined by the previous coding mode.
(See T.4/4.2.1.3.2.). */
int a0;
/*! \brief The first changing element on the reference line to the right of a0 and of
opposite colour to a0. */
int b1;
/*! \brief The length of the in-progress run of black or white. */
int run_length;
/*! \brief 2D horizontal mode control. */
int black_white;
/*! \brief TRUE if the current run is black */
int its_black;
/*! \brief The current step into the current row run-lengths buffer. */
int a_cursor;
/*! \brief The current step into the reference row run-lengths buffer. */
int b_cursor;
/*! \brief Incoming bit buffer for decompression. */
uint32_t rx_bitstream;
/*! \brief The number of bits currently in rx_bitstream. */
int rx_bits;
/*! \brief The number of bits to be skipped before trying to match the next code word. */
int rx_skip_bits;
/*! \brief Decoded pixel buffer. */
//uint32_t pixel_stream;
/*! \brief The number of bits currently in pixel_stream. */
//int tx_bits;
/*! \brief Current pixel row number. */
//int row;
/*! \brief The current number of consecutive bad rows. */
int curr_bad_row_run;
/*! \brief The longest run of consecutive bad rows seen in the current page. */
int longest_bad_row_run;
/*! \brief The total number of bad rows in the current page. */
int bad_rows;
/*! \brief Error and flow logging control */
//logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,59 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/t4_t6_encode.h - definitions for T.4/T.6 fax compression
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(_SPANDSP_PRIVATE_T4_T6_ENCODE_H_)
#define _SPANDSP_PRIVATE_T4_T6_ENCODE_H_
/*!
T.4 1D, T4 2D and T6 compressor state.
*/
struct t4_t6_encode_state_s
{
/*! \brief The minimum number of encoded bits per row. This is a timing thing
for hardware FAX machines. */
int min_bits_per_row;
/*! \brief The current maximum contiguous rows that may be 2D encoded. */
int max_rows_to_next_1d_row;
/*! \brief Number of rows left that can be 2D encoded, before a 1D encoded row
must be used. */
int rows_to_next_1d_row;
/*! \brief The number of runs currently in the reference row. */
int ref_steps;
/*! \brief Pointer to the byte containing the next image bit to transmit. */
int bit_pos;
/*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */
int bit_ptr;
/*! \brief Callback function to read a row of pixels from the image source. */
t4_row_read_handler_t row_read_handler;
/*! \brief Opaque pointer passed to row_read_handler. */
void *row_read_user_data;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,90 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/timezone.h - Timezone handling for time interpretation
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2010 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(_SPANDSP_PRIVATE_TIMEZONE_H_)
#define _SPANDSP_PRIVATE_TIMEZONE_H_
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#define TZNAME_MAX 255
/* The TZ_MAX_TIMES value below is enough to handle a bit more than a
* year's worth of solar time (corrected daily to the nearest second) or
* 138 years of Pacific Presidential Election time
* (where there are three time zone transitions every fourth year). */
#define TZ_MAX_TIMES 370
#if !defined(NOSOLAR)
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#else
/* Must be at least 14 for Europe/Riga as of Jan 12 1995,
* as noted by Earl Chew <earl@hpato.aus.hp.com>. */
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
#endif
#define TZ_BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
/* Time type information */
struct tz_ttinfo_s
{
int32_t gmtoff; /* UTC offset in seconds */
int isdst; /* Used to set tm_isdst */
int abbrind; /* Abbreviation list index */
int ttisstd; /* TRUE if transition is std time */
int ttisgmt; /* TRUE if transition is UTC */
};
/* Leap second information */
struct tz_lsinfo_s
{
time_t trans; /* Transition time */
int32_t corr; /* Correction to apply */
};
struct tz_state_s
{
int leapcnt;
int timecnt;
int typecnt;
int charcnt;
time_t ats[TZ_MAX_TIMES];
uint8_t types[TZ_MAX_TIMES];
struct tz_ttinfo_s ttis[TZ_MAX_TYPES];
char chars[TZ_BIGGEST(TZ_MAX_CHARS + 1, (2*(TZNAME_MAX + 1)))];
struct tz_lsinfo_s lsis[TZ_MAX_LEAPS];
};
struct tz_s
{
struct tz_state_s state;
char lcl_tzname[TZNAME_MAX + 1];
int lcl_is_set;
const char *tzname[2];
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,53 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t4_t6_decode.h - definitions for T.4/T.6 fax decoding
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003, 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if !defined(_SPANDSP_T4_T6_DECODE_H_)
#define _SPANDSP_T4_T6_DECODE_H_
/*! \page t4_t6_decode_page T.4 and T.6 FAX image decompression
\section t4_t6_decode_page_sec_1 What does it do?
The T.4 image compression and decompression routines implement the 1D and 2D
encoding methods defined in ITU specification T.4. They also implement the pure
2D encoding method defined in T.6. These are image compression algorithms used
for FAX transmission.
\section t4_t6_decode_page_sec_1 How does it work?
*/
typedef struct t4_t6_decode_state_s t4_t6_decode_state_t;
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,42 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t4_t6_encode.h - definitions for T.4/T.6 fax encoding
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003, 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if !defined(_SPANDSP_T4_T6_ENCODE_H_)
#define _SPANDSP_T4_T6_ENCODE_H_
typedef struct t4_t6_encode_state_s t4_t6_encode_state_t;
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,88 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* timezone.h - Timezone handling for time interpretation
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2010 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if !defined(_SPANDSP_TIMEZONE_H_)
#define _SPANDSP_TIMEZONE_H_
/*! \page timezone_page Timezone handling
\section timezone_sec_1 What does it do?
\section timezone_sec_2 How does it work?
*/
typedef struct tz_s tz_t;
enum
{
TM_SUNDAY = 0,
TM_MONDAY,
TM_TUESDAY,
TM_WEDNESDAY,
TM_THURSDAY,
TM_FRIDAY,
TM_SATURDAY
};
enum
{
TM_JANUARY = 0,
TM_FEBRUARY,
TM_MARCH,
TM_APRIL,
TM_MAY,
TM_JUNE,
TM_JULY,
TM_AUGUST,
TM_SEPTEMBER,
TM_OCTOBER,
TM_NOVEMBER,
TM_DECEMBER
};
#if defined(__cplusplus)
extern "C"
{
#endif
SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring);
SPAN_DECLARE(int) tz_release(tz_t *tz);
SPAN_DECLARE(int) tz_free(tz_t *tz);
SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tm, time_t t);
SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

822
libs/spandsp/src/timezone.c Normal file
View File

@ -0,0 +1,822 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* timezone.c - Timezone handling for time interpretation
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2010 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
/* Timezone processing might not seem like a DSP activity, but getting the headers
right on FAXes demands it. We need to handle multiple time zones within a process,
for FAXes related to different parts of the globe, so the system timezone handling
is not adequate. */
/* This timezone handling is derived from public domain software by Arthur David Olson
<arthur_david_olson@nih.gov> which you may download from ftp://elsie.nci.nih.gov/pub
at the time of writing. */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <assert.h>
#include "spandsp/telephony.h"
#include "spandsp/timezone.h"
#include "spandsp/private/timezone.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
#define SECS_PER_MIN 60
#define MINS_PER_HOUR 60
#define HOURS_PER_DAY 24
#define DAYS_PER_WEEK 7
#define DAYS_PER_NON_LEAP_YEAR 365
#define DAYS_PER_LEAP_YEAR 366
#define SECS_PER_HOUR (SECS_PER_MIN*MINS_PER_HOUR)
#define SECS_PER_DAY ((long int) SECS_PER_HOUR*HOURS_PER_DAY)
#define MONTHS_PER_YEAR 12
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
#define isleap(y) (((y)%4) == 0 && (((y)%100) != 0 || ((y)%400) == 0))
#define isleap_sum(a, b) isleap((a)%400 + (b)%400)
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
#define is_digit(c) ((unsigned int) (c) - '0' <= 9)
#define TZ_DEF_RULE_STRING ",M4.1.0,M10.5.0"
#define JULIAN_DAY 0 /* Jn - Julian day */
#define DAY_OF_YEAR 1 /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
static const char wildabbr[] = " ";
static const char gmt[] = "GMT";
struct tz_rule_s
{
int r_type; /* Type of rule--see below */
int r_day; /* Day number of rule */
int r_week; /* Week number of rule */
int r_mon; /* Month number of rule */
long int r_time; /* Transition time of rule */
};
static const int mon_lengths[2][MONTHS_PER_YEAR] =
{
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
static const int year_lengths[2] =
{
DAYS_PER_NON_LEAP_YEAR,
DAYS_PER_LEAP_YEAR
};
static int increment_overflow(int *number, int delta)
{
int number0;
number0 = *number;
*number += delta;
return (*number < number0) != (delta < 0);
}
/*- End of function --------------------------------------------------------*/
static void set_tzname(tz_t *tz)
{
struct tz_state_s *sp;
const struct tz_ttinfo_s *ttisp;
int i;
sp = &tz->state;
tz->tzname[0] = wildabbr;
tz->tzname[1] = wildabbr;
for (i = 0; i < sp->typecnt; i++)
{
ttisp = &sp->ttis[i];
tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind];
}
for (i = 0; i < sp->timecnt; i++)
{
ttisp = &sp->ttis[sp->types[i]];
tz->tzname[ttisp->isdst] = &sp->chars[ttisp->abbrind];
}
}
/*- End of function --------------------------------------------------------*/
/* Return the number of leap years through the end of the given year
where, to make the math easy, the answer for year zero is defined as zero. */
static int leaps_thru_end_of(const int y)
{
return (y >= 0) ? (y/4 - y/100 + y/400) : -(leaps_thru_end_of(-(y + 1)) + 1);
}
/*- End of function --------------------------------------------------------*/
static struct tm *time_sub(const time_t * const timep, const long int offset, const struct tz_state_s * const sp, struct tm * const tmp)
{
const struct tz_lsinfo_s *lp;
time_t tdays;
const int *ip;
int32_t corr;
int32_t seconds;
int32_t rem;
int idays;
int y;
int hit;
int i;
corr = 0;
hit = 0;
i = sp->leapcnt;
while (--i >= 0)
{
lp = &sp->lsis[i];
if (*timep >= lp->trans)
{
if (*timep == lp->trans)
{
hit = ((i == 0 && lp->corr > 0) || lp->corr > sp->lsis[i - 1].corr);
if (hit)
{
while (i > 0
&&
sp->lsis[i].trans == sp->lsis[i - 1].trans + 1
&&
sp->lsis[i].corr == sp->lsis[i - 1].corr + 1)
{
hit++;
--i;
}
}
}
corr = lp->corr;
break;
}
}
y = EPOCH_YEAR;
tdays = *timep/SECS_PER_DAY;
rem = *timep - tdays*SECS_PER_DAY;
while (tdays < 0 || tdays >= year_lengths[isleap(y)])
{
int newy;
time_t tdelta;
int idelta;
int leapdays;
tdelta = tdays / DAYS_PER_LEAP_YEAR;
idelta = tdelta;
if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
return NULL;
if (idelta == 0)
idelta = (tdays < 0) ? -1 : 1;
newy = y;
if (increment_overflow(&newy, idelta))
return NULL;
leapdays = leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1);
tdays -= ((time_t) newy - y)*DAYS_PER_NON_LEAP_YEAR;
tdays -= leapdays;
y = newy;
}
seconds = tdays*SECS_PER_DAY;
tdays = seconds/SECS_PER_DAY;
rem += seconds - tdays*SECS_PER_DAY;
/* Given the range, we can now fearlessly cast... */
idays = tdays;
rem += (offset - corr);
while (rem < 0)
{
rem += SECS_PER_DAY;
idays--;
}
while (rem >= SECS_PER_DAY)
{
rem -= SECS_PER_DAY;
idays++;
}
while (idays < 0)
{
if (increment_overflow(&y, -1))
return NULL;
idays += year_lengths[isleap(y)];
}
while (idays >= year_lengths[isleap(y)])
{
idays -= year_lengths[isleap(y)];
if (increment_overflow(&y, 1))
return NULL;
}
tmp->tm_year = y;
if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
return NULL;
tmp->tm_yday = idays;
/* The "extra" mods below avoid overflow problems. */
tmp->tm_wday = EPOCH_WDAY
+ ((y - EPOCH_YEAR) % DAYS_PER_WEEK)*(DAYS_PER_NON_LEAP_YEAR % DAYS_PER_WEEK)
+ leaps_thru_end_of(y - 1)
- leaps_thru_end_of(EPOCH_YEAR - 1)
+ idays;
tmp->tm_wday %= DAYS_PER_WEEK;
if (tmp->tm_wday < 0)
tmp->tm_wday += DAYS_PER_WEEK;
tmp->tm_hour = (int) (rem/SECS_PER_HOUR);
rem %= SECS_PER_HOUR;
tmp->tm_min = (int) (rem/SECS_PER_MIN);
/* A positive leap second requires a special
* representation. This uses "... ??:59:60" et seq. */
tmp->tm_sec = (int) (rem%SECS_PER_MIN) + hit;
ip = mon_lengths[isleap(y)];
for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; (tmp->tm_mon)++)
idays -= ip[tmp->tm_mon];
tmp->tm_mday = (int) (idays + 1);
tmp->tm_isdst = 0;
return tmp;
}
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, scan until a character that is not
* a valid character in a zone name is found. Return a pointer to that
* character. */
static const char *get_tzname(const char *strp)
{
char c;
while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+')
strp++;
return strp;
}
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a number from that string.
* Check that the number is within a specified range; if it is not, return
* NULL.
* Otherwise, return a pointer to the first character not part of the number. */
static const char *get_num(const char *strp, int * const nump, const int min, const int max)
{
char c;
int num;
if (strp == NULL || !is_digit(c = *strp))
return NULL;
num = 0;
do
{
num = num*10 + (c - '0');
if (num > max)
return NULL; /* Illegal value */
c = *++strp;
}
while (is_digit(c));
if (num < min)
return NULL; /* Illegal value */
*nump = num;
return strp;
}
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a number of seconds,
* in hh[:mm[:ss]] form, from the string.
* If any error occurs, return NULL.
* Otherwise, return a pointer to the first character not part of the number
* of seconds. */
static const char *get_secs(const char *strp, long int * const secsp)
{
int num;
/* HOURS_PER_DAY*DAYS_PER_WEEK - 1 allows quasi-Posix rules like
* "M10.4.6/26", which does not conform to Posix,
* but which specifies the equivalent of
* "02:00 on the first Sunday on or after 23 Oct". */
strp = get_num(strp, &num, 0, HOURS_PER_DAY*DAYS_PER_WEEK - 1);
if (strp == NULL)
return NULL;
*secsp = num*(long int) SECS_PER_HOUR;
if (*strp == ':')
{
strp = get_num(strp + 1, &num, 0, MINS_PER_HOUR - 1);
if (strp == NULL)
return NULL;
*secsp += num*SECS_PER_MIN;
if (*strp == ':')
{
/* SECS_PER_MIN allows for leap seconds. */
strp = get_num(strp + 1, &num, 0, SECS_PER_MIN);
if (strp == NULL)
return NULL;
*secsp += num;
}
}
return strp;
}
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract an offset, in
* [+-]hh[:mm[:ss]] form, from the string.
* If any error occurs, return NULL.
* Otherwise, return a pointer to the first character not part of the time. */
static const char *get_offset(const char *strp, long int * const offsetp)
{
int neg = 0;
if (*strp == '-')
{
neg = 1;
strp++;
}
else if (*strp == '+')
{
strp++;
}
strp = get_secs(strp, offsetp);
if (strp == NULL)
return NULL; /* Illegal time */
if (neg)
*offsetp = -*offsetp;
return strp;
}
/*- End of function --------------------------------------------------------*/
/* Given a pointer into a time zone string, extract a rule in the form
* date[/time]. See POSIX section 8 for the format of "date" and "time".
* If a valid rule is not found, return NULL.
* Otherwise, return a pointer to the first character not part of the rule. */
static const char *get_rule(const char *strp, struct tz_rule_s * const rulep)
{
if (*strp == 'J')
{
/* Julian day. */
rulep->r_type = JULIAN_DAY;
strp = get_num(strp + 1, &rulep->r_day, 1, DAYS_PER_NON_LEAP_YEAR);
}
else if (*strp == 'M')
{
/* Month, week, day. */
rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
strp = get_num(strp + 1, &rulep->r_mon, 1, MONTHS_PER_YEAR);
if (strp == NULL || *strp++ != '.')
return NULL;
strp = get_num(strp, &rulep->r_week, 1, 5);
if (strp == NULL || *strp++ != '.')
return NULL;
strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_WEEK - 1);
}
else if (is_digit(*strp))
{
/* Day of the year. */
rulep->r_type = DAY_OF_YEAR;
strp = get_num(strp, &rulep->r_day, 0, DAYS_PER_LEAP_YEAR - 1);
}
else
{
/* Invalid format */
return NULL;
}
if (strp == NULL)
return NULL;
if (*strp == '/')
{
/* Time specified. */
strp = get_secs(strp + 1, &rulep->r_time);
}
else
{
/* Default = 2:00:00 */
rulep->r_time = 2*SECS_PER_HOUR;
}
return strp;
}
/*- End of function --------------------------------------------------------*/
/* Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
* year, a rule, and the offset from UTC at the time that rule takes effect,
* calculate the Epoch-relative time that rule takes effect. */
static time_t trans_time(const time_t janfirst, const int year, const struct tz_rule_s * const rulep, const long int offset)
{
int leapyear;
time_t value;
int i;
int d;
int m1;
int yy0;
int yy1;
int yy2;
int dow;
value = 0;
leapyear = isleap(year);
switch (rulep->r_type)
{
case JULIAN_DAY:
/* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
* years.
* In non-leap years, or if the day number is 59 or less, just
* add SECS_PER_DAY times the day number-1 to the time of
* January 1, midnight, to get the day. */
value = janfirst + (rulep->r_day - 1)*SECS_PER_DAY;
if (leapyear && rulep->r_day >= 60)
value += SECS_PER_DAY;
break;
case DAY_OF_YEAR:
/* n - day of year.
* Just add SECS_PER_DAY times the day number to the time of
* January 1, midnight, to get the day. */
value = janfirst + rulep->r_day * SECS_PER_DAY;
break;
case MONTH_NTH_DAY_OF_WEEK:
/* Mm.n.d - nth "dth day" of month m. */
value = janfirst;
for (i = 0; i < rulep->r_mon - 1; i++)
value += mon_lengths[leapyear][i]*SECS_PER_DAY;
/* Use Zeller's Congruence to get day-of-week of first day of month. */
m1 = (rulep->r_mon + 9)%12 + 1;
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
yy1 = yy0/100;
yy2 = yy0%100;
dow = ((26*m1 - 2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1)%7;
if (dow < 0)
dow += DAYS_PER_WEEK;
/* "dow" is the day-of-week of the first day of the month. Get
* the day-of-month (zero-origin) of the first "dow" day of the
* month. */
d = rulep->r_day - dow;
if (d < 0)
d += DAYS_PER_WEEK;
for (i = 1; i < rulep->r_week; i++)
{
if (d + DAYS_PER_WEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
break;
d += DAYS_PER_WEEK;
}
/* "d" is the day-of-month (zero-origin) of the day we want. */
value += d*SECS_PER_DAY;
break;
}
/* "value" is the Epoch-relative time of 00:00:00 UTC on the day in
* question. To get the Epoch-relative time of the specified local
* time on that day, add the transition time and the current offset
* from UTC. */
return value + rulep->r_time + offset;
}
/*- End of function --------------------------------------------------------*/
/* Given a POSIX section 8-style TZ string, fill in the rule tables as
appropriate. */
static int tzparse(const char *name, struct tz_state_s * const sp, const int lastditch)
{
const char *stdname;
const char *dstname;
size_t stdlen;
size_t dstlen;
long int stdoffset;
long int dstoffset;
long int theirstdoffset;
long int theirdstoffset;
long int theiroffset;
unsigned char *typep;
char *cp;
int load_result;
int isdst;
int i;
int j;
int year;
struct tz_rule_s start;
struct tz_rule_s end;
time_t *atp;
time_t janfirst;
time_t starttime;
time_t endtime;
dstname = NULL;
stdname = name;
if (lastditch)
{
stdlen = strlen(name); /* Length of standard zone name */
name += stdlen;
if (stdlen >= sizeof(sp->chars))
stdlen = sizeof(sp->chars) - 1;
stdoffset = 0;
}
else
{
name = get_tzname(name);
stdlen = name - stdname;
if (stdlen < 3)
return -1;
if (*name == '\0')
return -1;
name = get_offset(name, &stdoffset);
if (name == NULL)
return -1;
}
load_result = -1;
if (load_result != 0)
sp->leapcnt = 0; /* So, we're off a little */
if (*name != '\0')
{
dstname = name;
name = get_tzname(name);
dstlen = name - dstname; /* Length of DST zone name */
if (dstlen < 3)
return -1;
if (*name != '\0' && *name != ',' && *name != ';')
{
if ((name = get_offset(name, &dstoffset)) == NULL)
return -1;
}
else
{
dstoffset = stdoffset - SECS_PER_HOUR;
}
if (*name == '\0' && load_result != 0)
name = TZ_DEF_RULE_STRING;
if (*name == ',' || *name == ';')
{
if ((name = get_rule(name + 1, &start)) == NULL)
return -1;
if (*name++ != ',')
return -1;
if ((name = get_rule(name, &end)) == NULL)
return -1;
if (*name != '\0')
return -1;
sp->typecnt = 2; /* Standard time and DST */
/* Two transitions per year, from EPOCH_YEAR to 2037. */
sp->timecnt = 2*(2037 - EPOCH_YEAR + 1);
if (sp->timecnt > TZ_MAX_TIMES)
return -1;
sp->ttis[0].gmtoff = -dstoffset;
sp->ttis[0].isdst = 1;
sp->ttis[0].abbrind = stdlen + 1;
sp->ttis[1].gmtoff = -stdoffset;
sp->ttis[1].isdst = 0;
sp->ttis[1].abbrind = 0;
atp = sp->ats;
typep = sp->types;
janfirst = 0;
for (year = EPOCH_YEAR; year <= 2037; year++)
{
starttime = trans_time(janfirst, year, &start, stdoffset);
endtime = trans_time(janfirst, year, &end, dstoffset);
if (starttime > endtime)
{
*atp++ = endtime;
*typep++ = 1; /* DST ends */
*atp++ = starttime;
*typep++ = 0; /* DST begins */
}
else
{
*atp++ = starttime;
*typep++ = 0; /* DST begins */
*atp++ = endtime;
*typep++ = 1; /* DST ends */
}
janfirst += year_lengths[isleap(year)]*SECS_PER_DAY;
}
}
else
{
if (*name != '\0')
return -1;
/* Initial values of theirstdoffset and theirdstoffset. */
theirstdoffset = 0;
for (i = 0; i < sp->timecnt; i++)
{
j = sp->types[i];
if (!sp->ttis[j].isdst)
{
theirstdoffset = -sp->ttis[j].gmtoff;
break;
}
}
theirdstoffset = 0;
for (i = 0; i < sp->timecnt; i++)
{
j = sp->types[i];
if (sp->ttis[j].isdst)
{
theirdstoffset = -sp->ttis[j].gmtoff;
break;
}
}
/* Initially we're assumed to be in standard time. */
isdst = FALSE;
theiroffset = theirstdoffset;
/* Now juggle transition times and types tracking offsets as you do. */
for (i = 0; i < sp->timecnt; i++)
{
j = sp->types[i];
sp->types[i] = sp->ttis[j].isdst;
if (sp->ttis[j].ttisgmt)
{
/* No adjustment to transition time */
}
else
{
/* If summer time is in effect, and the
* transition time was not specified as
* standard time, add the summer time
* offset to the transition time;
* otherwise, add the standard time
* offset to the transition time. */
/* Transitions from DST to DDST
* will effectively disappear since
* POSIX provides for only one DST
* offset. */
if (isdst && !sp->ttis[j].ttisstd)
sp->ats[i] += (dstoffset - theirdstoffset);
else
sp->ats[i] += (stdoffset - theirstdoffset);
}
theiroffset = -sp->ttis[j].gmtoff;
if (sp->ttis[j].isdst)
theirdstoffset = theiroffset;
else
theirstdoffset = theiroffset;
}
/* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */
sp->ttis[0].gmtoff = -stdoffset;
sp->ttis[0].isdst = FALSE;
sp->ttis[0].abbrind = 0;
sp->ttis[1].gmtoff = -dstoffset;
sp->ttis[1].isdst = TRUE;
sp->ttis[1].abbrind = stdlen + 1;
sp->typecnt = 2;
}
}
else
{
dstlen = 0;
sp->typecnt = 1; /* Only standard time */
sp->timecnt = 0;
sp->ttis[0].gmtoff = -stdoffset;
sp->ttis[0].isdst = 0;
sp->ttis[0].abbrind = 0;
}
sp->charcnt = stdlen + 1;
if (dstlen != 0)
sp->charcnt += dstlen + 1;
if ((size_t) sp->charcnt > sizeof(sp->chars))
return -1;
cp = sp->chars;
strncpy(cp, stdname, stdlen);
cp += stdlen;
*cp++ = '\0';
if (dstlen != 0)
{
strncpy(cp, dstname, dstlen);
cp[dstlen] = '\0';
}
return 0;
}
/*- End of function --------------------------------------------------------*/
static void tz_set(tz_t *tz, const char *tzstring)
{
const char *name = "";
struct tz_state_s *lclptr = &tz->state;
if (tzstring)
name = tzstring;
/* See if we are already set OK */
if (tz->lcl_is_set > 0 && strcmp(tz->lcl_tzname, name) == 0)
return;
tz->lcl_is_set = strlen(name) < sizeof(tz->lcl_tzname);
if (tz->lcl_is_set)
strcpy(tz->lcl_tzname, name);
if (name[0] == '\0')
{
/* User wants it fast rather than right, so, we're off a little. */
lclptr->leapcnt = 0;
lclptr->timecnt = 0;
lclptr->typecnt = 0;
lclptr->ttis[0].isdst = 0;
lclptr->ttis[0].gmtoff = 0;
lclptr->ttis[0].abbrind = 0;
strcpy(lclptr->chars, gmt);
}
else if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
{
tzparse(gmt, lclptr, TRUE);
}
set_tzname(tz);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) tz_localtime(tz_t *tz, struct tm *tmp, time_t t)
{
struct tz_state_s *sp;
const struct tz_ttinfo_s *ttisp;
int i;
sp = &tz->state;
if (sp->timecnt == 0 || t < sp->ats[0])
{
i = 0;
while (sp->ttis[i].isdst)
{
if (++i >= sp->typecnt)
{
i = 0;
break;
}
}
}
else
{
for (i = 1; i < sp->timecnt; i++)
{
if (t < sp->ats[i])
break;
}
i = (int) sp->types[i - 1];
}
ttisp = &sp->ttis[i];
time_sub(&t, ttisp->gmtoff, sp, tmp);
tmp->tm_isdst = ttisp->isdst;
tz->tzname[tmp->tm_isdst] = &sp->chars[ttisp->abbrind];
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) tz_tzname(tz_t *tz, int isdst)
{
return tz->tzname[(!isdst) ? 0 : 1];
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring)
{
if (tz == NULL)
{
if ((tz = (tz_t *) malloc(sizeof(*tz))) == NULL)
return NULL;
}
memset(tz, 0, sizeof(*tz));
tz->tzname[0] =
tz->tzname[1] = wildabbr;
tz_set(tz, tzstring);
return tz;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) tz_release(tz_t *tz)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) tz_free(tz_t *tz)
{
if (tz)
free(tz);
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,123 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* generate_striped_pages.c
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2010 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
/*
This program generates an TIFF image as a number of small image striped, rather than
the usual all in one page FAX images usually consist of in TIFF files.
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdio.h>
#include <inttypes.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>
#include <string.h>
#if defined(HAVE_TGMATH_H)
#include <tgmath.h>
#endif
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#include <tiffio.h>
#include "spandsp.h"
#define IMAGE_WIDTH 1728
#define IMAGE_LENGTH 2600
#define ROWS_PER_STRIPE 37
int main(int argc, char *argv[])
{
TIFF *tiff_file;
uint8_t image_buffer[10000];
int image_size;
time_t now;
struct tm *tm;
char buf[256 + 1];
int i;
if ((tiff_file = TIFFOpen("striped.tif", "w")) == NULL)
return -1;
TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, COMPRESSION_CCITT_T6);
TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, (int32_t) ROWS_PER_STRIPE);
TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
TIFFSetField(tiff_file, TIFFTAG_XRESOLUTION, 204.0f);
TIFFSetField(tiff_file, TIFFTAG_YRESOLUTION, 196.0f);
TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp");
TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, "host");
TIFFSetField(tiff_file, TIFFTAG_FAXSUBADDRESS, "1111");
TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Image in stripes");
TIFFSetField(tiff_file, TIFFTAG_MAKE, "spandsp");
TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy");
time(&now);
tm = localtime(&now);
sprintf(buf,
"%4d/%02d/%02d %02d:%02d:%02d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
TIFFSetField(tiff_file, TIFFTAG_DATETIME, buf);
TIFFSetField(tiff_file, TIFFTAG_FAXRECVTIME, 10);
TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, IMAGE_WIDTH);
TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, IMAGE_LENGTH);
TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1);
image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8;
memset(image_buffer, 0x18, image_size);
for (i = 0; i < IMAGE_LENGTH/ROWS_PER_STRIPE; i++)
{
if (IMAGE_LENGTH > (i + 1)*ROWS_PER_STRIPE)
image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8;
else
image_size = IMAGE_WIDTH*(IMAGE_LENGTH - i*ROWS_PER_STRIPE)/8;
if (TIFFWriteEncodedStrip(tiff_file, i, image_buffer, image_size) < 0)
return -1;
}
TIFFWriteDirectory(tiff_file);
TIFFClose(tiff_file);
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,189 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bitstream_tests.c
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2007 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \page bitstream_tests_page Bitstream tests
\section bitstream_tests_page_sec_1 What does it do?
\section bitstream_tests_page_sec_2 How is it used?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
//#if defined(WITH_SPANDSP_INTERNALS)
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
//#endif
#include "spandsp.h"
uint8_t buffer[256];
#define PATTERN 0x11111111
#define SEQUENCE_LENGTH 17
uint8_t left[] =
{
0x28, /* 2 of 4, 3, 2, 1 */
0xC8, /* 1 of 6, 5, 2 of 4 */
0xAE, /* 3 of 7, 5 of 6 */
0x67, /* 4 of 8, 4 of 7 */
0x74, /* 4 of 9, 4 of 8 */
0x43, /* 3 of 10, 5 of 9 */
0x32, /* 1 of 11, 7 of 10 */
0xAA, /* 8 of 11 */
0xAE, /* 6 of 12, 2 of 11 */
0xED, /* 2 of 13, 6 of 12 */
0x99, /* 8 of 13 */
0x8E, /* 5 of 14, 3 of 13 */
0xEE, /* 8 of 14 */
0xEE, /* 7 of 15, 1 of 14 */
0xEE, /* 8 of 15 */
0xFF, /* 8 of 16 */
0xFF, /* 8 of 16 */
0x88, /* 8 of 17 */
0x88, /* 8 of 17 */
0x00 /* 1 of 17 */
};
uint8_t right[] =
{
0xD2, /* 1, 2, 3, 2 of 4 */
0x90, /* 2 of 4, 5, 1 of 6 */
0xCA, /* 5 of 6, 3 of 7 */
0x7C, /* 4 of 7, 4 of 8 */
0x87, /* 4 of 8, 4 of 9 */
0x28, /* 5 of 9, 3 of 10 */
0x33, /* 7 of 10, 1 of 11 */
0x55, /* 8 of 11 */
0xED, /* 2 of 11, 6 of 12 */
0x2E, /* 6 of 12, 2 of 13 */
0x33, /* 8 of 13 */
0xEB, /* 3 of 13, 5 of 14 */
0xEE, /* 8 of 14 */
0xDC, /* 1 of 14, 7 of 15 */
0xDD, /* 8 of 15 */
0xFF, /* 8 of 16 */
0xFF, /* 8 of 16 */
0x10, /* 8 of 17 */
0x11, /* 8 of 17 */
0x01 /* 1 of 17 */
};
int main(int argc, char *argv[])
{
int i;
bitstream_state_t state;
bitstream_state_t *s;
const uint8_t *r;
uint8_t *w;
uint8_t *cc;
unsigned int x;
int total_bits;
s = bitstream_init(&state, TRUE);
w = buffer;
total_bits = 0;
for (i = 0; i < SEQUENCE_LENGTH; i++)
{
bitstream_put(s, &w, PATTERN*i, i + 1);
total_bits += (i + 1);
}
bitstream_flush(s, &w);
printf("%d bits written\n", total_bits);
for (cc = buffer; cc < w; cc++)
printf("%02X ", *cc);
printf("\n");
for (cc = right; cc < right + sizeof(right); cc++)
printf("%02X ", *cc);
printf("\n");
if ((w - buffer) != sizeof(right) || memcmp(buffer, right, sizeof(right)))
{
printf("Test failed\n");
exit(2);
}
s = bitstream_init(&state, TRUE);
r = buffer;
for (i = 0; i < SEQUENCE_LENGTH; i++)
{
x = bitstream_get(s, &r, i + 1);
if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1)))
{
printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1)));
printf("Test failed\n");
exit(2);
}
}
s = bitstream_init(&state, FALSE);
w = buffer;
total_bits = 0;
for (i = 0; i < SEQUENCE_LENGTH; i++)
{
bitstream_put(s, &w, PATTERN*i, i + 1);
total_bits += (i + 1);
}
bitstream_flush(s, &w);
printf("%d bits written\n", total_bits);
for (cc = buffer; cc < w; cc++)
printf("%02X ", *cc);
printf("\n");
for (cc = left; cc < left + sizeof(left); cc++)
printf("%02X ", *cc);
printf("\n");
if ((w - buffer) != sizeof(left) || memcmp(buffer, left, sizeof(left)))
{
printf("Test failed\n");
exit(2);
}
s = bitstream_init(&state, FALSE);
r = buffer;
for (i = 0; i < SEQUENCE_LENGTH; i++)
{
x = bitstream_get(s, &r, i + 1);
if (x != ((PATTERN*i) & ((1 << (i + 1)) - 1)))
{
printf("Error 0x%X 0x%X\n", x, ((PATTERN*i) & ((1 << (i + 1)) - 1)));
printf("Test failed\n");
exit(2);
}
}
printf("Tests passed.\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,452 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* image_translate_tests.c - Tests for the image translation routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
/*! \page image_translate_tests_page Image translation tests
\section image_translate_tests_page_sec_1 What does it do?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
//#if defined(WITH_SPANDSP_INTERNALS)
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
//#endif
#include "spandsp.h"
#define INPUT_TIFF_FILE_NAME "../test-data/local/lenna-colour.tif"
typedef struct
{
const uint8_t *image;
int width;
int length;
int current_row;
int bytes_per_pixel;
} image_descriptor_t;
static void display_row(int row, int width, uint8_t buf[])
{
int i;
int test_pixel;
printf("%3d: ", row);
for (i = 0; i < width; i++)
{
test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01;
printf("%c", (test_pixel) ? ' ' : '@');
}
printf("\n");
}
/*- End of function --------------------------------------------------------*/
static int test_dithered_50_by_50(int row, int width, uint8_t buf[])
{
static const char *image[50] =
{
" 0: @ @ @ @ @ @ @ @@ @@@@@@@@@@@@@@",
" 1: @ @ @ @ @ @ @ @ @ @@ @@ @ @ @ @ @@@@",
" 2: @ @ @ @ @ @ @ @@ @ @ @@@ @@@@@@ @@",
" 3: @ @ @ @ @ @ @ @ @ @ @@@ @@@@ @@@@@@",
" 4: @ @ @ @ @ @ @ @ @ @@@ @ @@ @@@@ @@@@",
" 5: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@@@@",
" 6: @ @ @ @ @ @ @@ @@@@ @@@ @@@ @@ @",
" 7: @ @ @ @ @ @ @ @ @ @@ @@ @ @@ @@@@@@",
" 8: @ @ @ @ @ @ @ @ @@@ @@@@@@@@@ @@@",
" 9: @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ @ @@@@@",
" 10: @ @ @ @ @ @@ @ @@ @@@@@@@@@@@@@",
" 11: @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@ @@ @@",
" 12: @ @ @ @ @ @ @ @ @ @@ @@@@@@ @@@@@@@",
" 13: @ @ @ @ @ @ @ @ @@ @ @ @ @ @@@@@ @@@",
" 14: @ @ @ @ @ @ @ @@ @@@ @@@ @ @@@@@@",
" 15: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@@ @@",
" 16: @ @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@@",
" 17: @ @ @ @ @ @ @ @ @ @@ @@ @@ @@ @@@@@@@",
" 18: @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@ @ @@@",
" 19: @ @ @ @ @ @ @ @ @@@ @@@ @ @@@@@@@",
" 20: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@@@@ @@@ @",
" 21: @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@",
" 22: @ @ @ @ @ @@ @ @ @ @ @@ @@@@@@@ @@ @@",
" 23: @ @ @ @ @ @ @ @@ @@ @@ @ @ @@@@@@@",
" 24: @ @ @ @ @@ @ @ @@ @ @ @@@@@@ @@@@@",
" 25: @ @ @ @ @ @ @ @ @ @ @@@@@ @ @@@@ @@",
" 26: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@ @@@@@",
" 27: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@ @@@@@@@",
" 28: @ @ @ @ @ @ @ @ @@@ @@@ @@@ @@ @@",
" 29: @ @ @ @ @ @ @ @ @@ @ @@ @ @@ @@@@@@@",
" 30: @ @ @ @ @ @ @ @ @ @ @ @@@@@@@ @@@@@",
" 31: @ @ @ @ @ @ @ @ @ @@@@ @ @ @@@@ @@",
" 32: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@ @@@@@",
" 33: @ @ @ @ @ @ @ @@@ @@ @ @ @@@@@@@",
" 34: @ @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@ @ @@@",
" 35: @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@",
" 36: @ @ @ @ @ @ @ @ @@ @@@ @@@@@@@ @@@ @",
" 37: @ @ @ @ @ @ @ @ @ @ @@ @ @ @@@@@@@",
" 38: @ @ @ @ @ @ @ @ @@ @@ @@@@@@@ @@ @@",
" 39: @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@",
" 40: @ @ @ @ @ @ @ @ @ @@ @@ @@@@ @@@@@",
" 41: @ @ @ @ @ @ @ @ @ @@ @ @@ @@@ @@@@ @@",
" 42: @ @ @ @ @ @ @@ @@ @@ @@ @@@ @@@@@",
" 43: @ @ @ @ @ @ @ @ @ @ @@ @@@ @@@@@@@",
" 44: @ @ @ @ @ @ @ @ @ @ @@@ @@@ @@@ @@ @@",
" 45: @ @ @ @ @ @ @@ @ @ @ @@ @@@@@@@",
" 46: @ @ @ @ @ @ @ @ @ @ @ @@ @@@@@@@@@ @@@@@",
" 47: @ @ @ @ @ @ @ @ @ @@ @ @ @ @@@@ @@",
" 48: @ @ @ @ @ @ @@ @ @@ @@@@@@ @@@@@",
" 49: @ @ @ @ @ @ @ @ @ @ @ @@ @@ @ @ @@@@@@@"
};
int i;
int match;
int ref_pixel;
int test_pixel;
match = 0;
for (i = 0; i < width; i++)
{
ref_pixel = (image[row][i + 5] == ' ');
test_pixel = (buf[i >> 3] >> (7 - (i & 7))) & 0x01;
if (ref_pixel != test_pixel)
match = -1;
}
return match;
}
/*- End of function --------------------------------------------------------*/
static int row_read(void *user_data, uint8_t buf[], size_t len)
{
image_descriptor_t *im;
im = (image_descriptor_t *) user_data;
if (im->current_row >= im->length)
return 0;
memcpy(buf, &im->image[im->current_row*im->width*im->bytes_per_pixel], len);
im->current_row++;
return len;
}
/*- End of function --------------------------------------------------------*/
static void get_flattened_image(image_translate_state_t *s, int compare)
{
int i;
int len;
uint8_t row_buf[5000];
for (i = 0; i < s->output_length; i++)
{
if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != (s->output_width + 7)/8)
{
printf("Image finished early - %d %d\n", len, (s->output_width + 7)/8);
exit(2);
}
display_row(i, s->output_width, row_buf);
if (compare)
{
if (test_dithered_50_by_50(i, s->output_width, row_buf))
{
printf("Dithered image mismatch at row %d\n", i);
printf("Test failed\n");
exit(2);
}
}
}
if ((len = image_translate_row(s, row_buf, (s->output_width + 7)/8)) != 0)
{
printf("Image finished late - %d %d\n", len, (s->output_width + 7)/8);
exit(2);
}
}
/*- End of function --------------------------------------------------------*/
static void dither_tests_gray16(void)
{
int i;
int j;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
uint16_t image[50*50];
image_descriptor_t im;
printf("Dithering from a 16 bit per sample gray scale to bi-level\n");
im.image = (const uint8_t *) image;
im.width = 50;
im.length = 50;
im.bytes_per_pixel = 2;
im.current_row = 0;
for (i = 0; i < im.length; i++)
{
for (j = 0; j < im.width; j++)
image[i*im.width + j] = j*1200;
}
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_16, im.width, im.length, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
static void dither_tests_gray8(void)
{
int i;
int j;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
uint8_t image[50*50];
image_descriptor_t im;
printf("Dithering from a 8 bit per sample gray scale to bi-level\n");
im.image = image;
im.width = 50;
im.length = 50;
im.bytes_per_pixel = 1;
im.current_row = 0;
for (i = 0; i < im.length; i++)
{
for (j = 0; j < im.width; j++)
image[i*im.width + j] = j*1200/256;
}
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_GRAY_8, im.width, im.length, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
static void dither_tests_colour16(void)
{
int i;
int j;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
uint16_t image[50*50*3];
image_descriptor_t im;
printf("Dithering from a 3x16 bit per sample colour to bi-level\n");
im.image = (const uint8_t *) image;
im.width = 50;
im.length = 50;
im.bytes_per_pixel = 6;
im.current_row = 0;
for (i = 0; i < im.length; i++)
{
for (j = 0; j < im.width; j++)
{
image[i*3*im.width + 3*j + 0] = j*1200;
image[i*3*im.width + 3*j + 1] = j*1200;
image[i*3*im.width + 3*j + 2] = j*1200;
}
}
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_16, im.width, im.length, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
static void dither_tests_colour8(void)
{
int i;
int j;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
uint8_t image[50*50*3];
image_descriptor_t im;
printf("Dithering from a 3x8 bit per sample colour to bi-level\n");
im.image = image;
im.width = 50;
im.length = 50;
im.bytes_per_pixel = 3;
im.current_row = 0;
for (i = 0; i < im.length; i++)
{
for (j = 0; j < im.width; j++)
{
image[i*3*im.width + 3*j + 0] = j*1200/256;
image[i*3*im.width + 3*j + 1] = j*1200/256;
image[i*3*im.width + 3*j + 2] = j*1200/256;
}
}
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, -1, row_read, &im);
get_flattened_image(s, TRUE);
}
/*- End of function --------------------------------------------------------*/
static void grow_tests_colour8(void)
{
int i;
int j;
image_translate_state_t resize;
image_translate_state_t *s1 = &resize;
uint8_t image[50*50*3];
image_descriptor_t im;
printf("Image growth tests\n");
im.image = image;
im.width = 50;
im.length = 50;
im.bytes_per_pixel = 3;
im.current_row = 0;
for (i = 0; i < im.length; i++)
{
for (j = 0; j < im.width; j++)
{
image[i*3*im.width + 3*j + 0] = j*1200/256;
image[i*3*im.width + 3*j + 1] = j*1200/256;
image[i*3*im.width + 3*j + 2] = j*1200/256;
}
}
s1 = image_translate_init(s1, IMAGE_TRANSLATE_FROM_COLOUR_8, im.width, im.length, 200, row_read, &im);
get_flattened_image(s1, FALSE);
}
/*- End of function --------------------------------------------------------*/
static void lenna_tests(int output_width, const char *file)
{
TIFF *in_file;
TIFF *out_file;
int image_width;
int image_length;
int output_length;
uint8_t *image;
uint8_t *image2;
int len;
int total;
int16_t bits_per_sample;
int16_t samples_per_pixel;
int i;
int n;
image_translate_state_t bw;
image_translate_state_t *s = &bw;
image_descriptor_t im;
printf("Dithering Lenna from colour to bi-level test\n");
if ((in_file = TIFFOpen(INPUT_TIFF_FILE_NAME, "r")) == NULL)
return;
image_width = 0;
TIFFGetField(in_file, TIFFTAG_IMAGEWIDTH, &image_width);
if (image_width <= 0)
return;
image_length = 0;
TIFFGetField(in_file, TIFFTAG_IMAGELENGTH, &image_length);
if (image_length <= 0)
return;
bits_per_sample = 0;
TIFFGetField(in_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
samples_per_pixel = 0;
TIFFGetField(in_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
printf("Original image is %d x %d, %d bits per sample, %d samples per pixel\n", image_width, image_length, bits_per_sample, samples_per_pixel);
if ((image = malloc(image_width*image_length*samples_per_pixel)) == NULL)
return;
for (total = 0, i = 0; i < 1000; i++)
{
len = TIFFReadEncodedStrip(in_file, i, &image[total], image_width*image_length*samples_per_pixel - total);
if (len <= 0)
break;
total += len;
if (total == image_width*image_length*samples_per_pixel)
{
printf("Done\n");
break;
}
}
printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel);
TIFFClose(in_file);
im.image = image;
im.width = image_width;
im.length = image_length;
im.current_row = 0;
im.bytes_per_pixel = samples_per_pixel;
s = image_translate_init(s, IMAGE_TRANSLATE_FROM_COLOUR_8, image_width, image_length, output_width, row_read, &im);
output_width = image_translate_get_output_width(s);
output_length = image_translate_get_output_length(s);
if ((out_file = TIFFOpen(file, "w")) == NULL)
return;
TIFFSetField(out_file, TIFFTAG_IMAGEWIDTH, output_width);
TIFFSetField(out_file, TIFFTAG_IMAGELENGTH, output_length);
TIFFSetField(out_file, TIFFTAG_BITSPERSAMPLE, 1);
TIFFSetField(out_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(out_file, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(out_file, TIFFTAG_ROWSPERSTRIP, -1);
TIFFSetField(out_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
TIFFSetField(out_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
TIFFSetField(out_file, TIFFTAG_PAGENUMBER, 0, 1);
TIFFSetField(out_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
TIFFSetField(out_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
printf("Input %d x %d, output %d x %d\n", image_width, image_length, output_width, output_length);
if ((image2 = malloc(output_width*output_length/8)) == NULL)
return;
memset(image2, 0, output_width*output_length/8);
n = 0;
for (i = 0; i < output_length; i++)
n += image_translate_row(s, &image2[n], output_width/8);
TIFFWriteEncodedStrip(out_file, 0, image2, output_width*output_length/8);
TIFFWriteDirectory(out_file);
TIFFClose(out_file);
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char **argv)
{
#if 1
dither_tests_gray16();
dither_tests_gray8();
dither_tests_colour16();
dither_tests_colour8();
#endif
#if 1
grow_tests_colour8();
#endif
#if 1
lenna_tests(0, "lenna-bw.tif");
lenna_tests(1728, "lenna-bw-1728.tif");
lenna_tests(200, "lenna-bw-200.tif");
#endif
printf("Tests passed.\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,311 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* saturated_tests.c
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \page saturated_tests_page Saturated arithmetic function tests
\section saturated_tests_page_sec_1 What does it do?
???.
\section saturated_tests_page_sec_2 How does it work?
???.
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#include "spandsp.h"
int main(int argc, char *argv[])
{
printf("Testing 16 bit saturation\n");
if (saturate16(10000) != 10000
||
saturate16(-10000) != -10000
||
saturate16(32767) != 32767
||
saturate16(-32768) != -32768
||
saturate16(32768) != 32767
||
saturate16(-32769) != -32768)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 15 bit saturation\n");
if (saturate15(10000) != 10000
||
saturate15(-10000) != -10000
||
saturate15(16383) != 16383
||
saturate15(-16384) != -16384
||
saturate15(16384) != 16383
||
saturate15(-16385) != -16384)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit unsigned saturation\n");
if (saturateu16(10000) != 10000
||
saturateu16(32767) != 32767
||
saturateu16(65535) != 65535
||
saturateu16(65536) != 65535)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 8 bit unsigned saturation\n");
if (saturateu8(100) != 100
||
saturateu8(127) != 127
||
saturateu8(255) != 255
||
saturateu8(256) != 255)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit saturation from float\n");
if (fsaturatef(10000.0f) != 10000
||
fsaturatef(-10000.0f) != -10000
||
fsaturatef(32767.0f) != 32767
||
fsaturatef(-32768.0f) != -32768
||
fsaturatef(32768.0f) != 32767
||
fsaturatef(-32769.0f) != -32768)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit saturation from double\n");
if (fsaturate(10000.0) != 10000
||
fsaturate(-10000.0) != -10000
||
fsaturate(32767.0) != 32767
||
fsaturate(-32768.0) != -32768
||
fsaturate(32768.0) != 32767
||
fsaturate(-32769.0) != -32768)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit fast saturation from float\n");
if (ffastsaturatef(10000.0f) != 10000
||
ffastsaturatef(-10000.0f) != -10000
||
ffastsaturatef(32767.0f) != 32767
||
ffastsaturatef(-32768.0f) != -32768
||
ffastsaturatef(32768.0f) != 32767
||
ffastsaturatef(-32769.0f) != -32768)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit fast saturation from double\n");
if (ffastsaturate(10000.0) != 10000
||
ffastsaturate(-10000.0) != -10000
||
ffastsaturate(32767.0) != 32767
||
ffastsaturate(-32768.0) != -32768
||
ffastsaturate(32768.0) != 32767
||
ffastsaturate(-32769.0) != -32768)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit float saturation from float\n");
if (ffsaturatef(10000.0f) != 10000.0f
||
ffsaturatef(-10000.0f) != -10000.0f
||
ffsaturatef(32767.0f) != 32767.0f
||
ffsaturatef(-32768.0f) != -32768.0f
||
ffsaturatef(32768.0f) != 32767.0f
||
ffsaturatef(-32769.0f) != -32768.0f)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit double saturation from double\n");
if (ffsaturate(10000.0) != 10000.0
||
ffsaturate(-10000.0) != -10000.0
||
ffsaturate(32767.0) != 32767.0
||
ffsaturate(-32768.0) != -32768.0
||
ffsaturate(32768.0) != 32767.0
||
ffsaturate(-32769.0) != -32768.0)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit add\n");
if (saturated_add16(10000, 10000) != 20000
||
saturated_add16(10000, -10000) != 0
||
saturated_add16(-10000, 10000) != 0
||
saturated_add16(-10000, -10000) != -20000
||
saturated_add16(-30000, -30000) != INT16_MIN
||
saturated_add16(30000, 30000) != INT16_MAX)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 32 bit add\n");
if (saturated_add32(10000, 10000) != 20000
||
saturated_add32(10000, -10000) != 0
||
saturated_add32(-10000, 10000) != 0
||
saturated_add32(-10000, -10000) != -20000
||
saturated_add32(-2000000000, -2000000000) != INT32_MIN
||
saturated_add32(2000000000, 2000000000) != INT32_MAX)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit subtract\n");
if (saturated_sub16(10000, 10000) != 0
||
saturated_sub16(10000, -10000) != 20000
||
saturated_sub16(-10000, 10000) != -20000
||
saturated_sub16(-10000, -10000) != 0
||
saturated_sub16(-30000, 30000) != INT16_MIN
||
saturated_sub16(30000, -30000) != INT16_MAX)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 32 bit subtract\n");
if (saturated_sub32(10000, 10000) != 0
||
saturated_sub32(10000, -10000) != 20000
||
saturated_sub32(-10000, 10000) != -20000
||
saturated_sub32(-10000, -10000) != 0
||
saturated_sub32(-2000000000, 2000000000) != INT32_MIN
||
saturated_sub32(2000000000, -2000000000) != INT32_MAX)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 x 16 => 16 bit multiply\n");
if (saturated_mul16(100, 100) != 0
||
saturated_mul16(255, 255) != 1
||
saturated_mul16(32767, -32768) != -32767
||
saturated_mul16(-32768, 32767) != -32767
||
saturated_mul16(32767, 32767) != 32766
||
saturated_mul16(-32768, -32768) != 32767)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 x 16 => 32 bit multiply\n");
if (saturated_mul16_32(100, 100) != 20000
||
saturated_mul16_32(-100, 100) != -20000
||
saturated_mul16_32(32767, -32768) != -2147418112
||
saturated_mul16_32(-32768, 32767) != -2147418112
||
saturated_mul16_32(32767, 32767) != 2147352578
||
saturated_mul16_32(-32768, -32768) != -2147483648)
{
printf("Test failed.\n");
exit(2);
}
printf("Testing 16 bit absolute\n");
if (saturated_abs16(10000) != 10000
||
saturated_abs16(-10000) != 10000
||
saturated_abs16(32767) != 32767
||
saturated_abs16(-32768) != 32767)
{
printf("Test failed.\n");
exit(2);
}
printf("Tests passed.\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,86 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* timezone_tests.c - Timezone handling for time interpretation
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2010 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \page timezone_tests_page Timezone handling tests
\section timezone_tests_page_sec_1 What does it do?
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
//#if defined(WITH_SPANDSP_INTERNALS)
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
//#endif
#include "spandsp.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
int main(int argc, char *argv[])
{
struct tm tms;
struct tm *tmp = &tms;
time_t ltime;
tz_t *tz;
/* Get the current time */
ltime = time(NULL);
/* Compute the local current time now for several localities, based on Posix tz strings */
tz = tz_init(NULL, "GMT0GMT0,M10.5.0,M3.5.0");
tz_localtime(tz, tmp, ltime);
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
tz_init(tz, "CST-8CST-8,M10.5.0,M3.5.0");
tz_localtime(tz, tmp, ltime);
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
tz_init(tz, "AEST-10AEDT-11,M10.5.0,M3.5.0");
tz_localtime(tz, tmp, ltime);
printf("Local time is %02d:%02d:%02d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
printf("Time zone is %s\n", tz_tzname(tz, tmp->tm_isdst));
tz_free(tz);
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,33 @@
#!/bin/sh
#
# spandsp fax tests
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 2.1,
# as published by the Free Software Foundation.
#
# This program 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
run_tsb85_test()
{
rm -f fax_tests_1.tif
echo ./tsb85_tests ${TEST}
./tsb85_tests -x ../spandsp/fax-tests.xml ${TEST} 2>xyzzy2
RETVAL=$?
if [ $RETVAL != 0 ]
then
echo tsb85_tests ${TEST} failed!
exit $RETVAL
fi
}
for TEST in PPS-MPS-lost-PPS ; do
run_tsb85_test
done