rpms/pxsup2dast/devel pxsup2dast.c,NONE,1.1 pxsup2dast.spec,NONE,1.1

Martin Gansser martinkg at rpmfusion.org
Sat Jun 8 17:40:51 CEST 2013


Author: martinkg

Update of /cvs/free/rpms/pxsup2dast/devel
In directory old02.ovh.rpmfusion.lan:/tmp/cvs-serv17640/devel

Added Files:
	pxsup2dast.c pxsup2dast.spec 
Log Message:



--- NEW FILE pxsup2dast.c ---
#if 0 /*
 #
 # pxsup2dast.c version 2012-07-04
 #
 # Project X sup to dvdauthor subtitle xml file.
 # too ät iki piste fi
 #
 # Last Modified: Wed 04 Jul 2012 22:46:25 EEST too
 #
 # To compile this program, enter `sh pxsup2dast.c'.
 # -------------------------------------------------
 #
 # This is currently wery picky what this expects of ProjectX .sup to contain.
 # Update: 2005/07/02 Not so picky anymore, but control sequence parsing is
 # not perfect (yet!?)
 #
 # NOTE: son2dast.sh
 # '''''''''''''''''
 # If you have problems with subtitle colors then your source file may
 # have subtitle images that use more than 4 colors. In that case the
 # tool son2dast.sh may help you (available at the same location this
 # file is provided by the author).
 # (son2dast.sh may provide better quality than alternative solutions)

 # Change 2012-07-04: Added the above note about son2dast.sh.
 #
 # Change 2011-06-29: Quotes /&/, /"/, /'/, /</ and />/ in xml file
 # (Thanks Frank van den Beuken for informing the issue).
 #
 # Change 2011-06-28: Rounding error in pts2ts fixed (thanks to
 # Frank van den Beuken for noticing and fixing this).
 #
 # Change 2010-08-29: Initial handling of 0x07 control code (from
 # Simon Liddicott). Currently just ignores contents but doesn't choke on
 # it anymore...
 #
 # Change 2009-08-09: Renamed getline() as getpixelline() (to avoid function
 # name collision. Fixed GPL version to 2 (only). Thanks Ville Skyttä.
 #
 # Change 2009-01-10: Added subtitle indexing change (fix) from patch
 # sent by Ian Stewart.
 #
 # This program is released under GNU GPL version 2. Check
 # http://www.fsf.org/licenses/licenses.html
 # to get your own copy of the GPL v2 license.
 #
 # Shell script to compile this program follows...

 TRG=`basename $0 .c`; rm -f "$TRG" "${TRG}_defs.hg"
 trap 'rm -f "${TRG}_defs.hg"' 0; perl -x "$0" "$0" > "${TRG}_defs.hg"
 WARN="-Wall -Wstrict-prototypes -pedantic -Wno-long-long"
 WARN="$WARN -Wcast-align -Wpointer-arith " # -Wfloat-equal #-Werror
 WARN="$WARN -W -Wwrite-strings -Wcast-qual -Wshadow" # -Wconversion
 lastrun() { echo "$@"; "$@"; exit $?; }
 #lastrun ${CC:-gcc} -ggdb $WARN "$@" -o "$TRG" "$0" -DCDATE="\"`date`\"" -lz
 lastrun ${CC:-gcc} -O2 $WARN "$@" -o "$TRG" "$0" -DCDATE="\"`date`\"" -lz

# Perl program to create static function prototypes follows:

#! perl
print "/\*\n * Autogenerated by $0 perlcode -- do not edit.\n *\/";
while ($_ = shift @ARGV) {
  open(I, "$_") || die "Can not open input file $_: $!\n";
  print "\n\n/\*  $_  *\/\n\n";
  $state = 0; while (<I>) {
    print ("$1\n"), next if /(.*?)\s*\/\*.*\s+protoline\s.*\*\//;
    @l = '', $state = 1 if /^static/;
    if ($state) {
      $state = 0, next if /;/;
      #chop;
      $state = 2 if /\(/;
      s|\s*\/\*\s+protoadd\s+(.*)\s+\*\/\s*|\t$1|;
      s/\(\)/\(void\)/;
      if (s|\s*{.*||) {
          chop; print (@l, "$_;\n") if ($state > 1); $state = 0; next; }
      push @l, "\n$_"; }}
  close I; }
print "\n";
__END__;

*/
#endif

typedef enum { false = 0, true = 1 }	bool;
typedef unsigned char			bool8;


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <setjmp.h>
#include <zlib.h>

#if 1
/* this is all speed, not so much portability -- using C99 features... */
#include <stdint.h>

typedef int8_t  ei8;		typedef uint8_t  eu8;
typedef int16_t ei16;		typedef uint16_t eu16;
typedef int32_t ei32;		typedef uint32_t eu32;

typedef int_least8_t  li8;	typedef uint_least8_t  lu8;
typedef int_least16_t li16;	typedef uint_least16_t lu16;
typedef int_least32_t li32;	typedef uint_least32_t lu32;

typedef int_fast8_t  fi8;	typedef uint_fast8_t  fu8;
typedef int_fast16_t fi16;	typedef uint_fast16_t fu16;
typedef int_fast32_t fi32;	typedef uint_fast32_t fu32;
#endif


#if (__GNUC__ >= 3)
#define GCCATTR_PRINTF(m, n) __attribute__ ((format (printf, m, n)))
#define GCCATTR_UNUSED	 __attribute ((unused))
#define GCCATTR_NORETURN __attribute ((noreturn))
#define GCCATTR_CONST	 __attribute ((const))

#define from_type(ft, v) \
  __builtin_choose_expr (__builtin_types_compatible_p (typeof (v), ft),	\
		       (v), (void)0)

#define checked_cast(tf, ft, v) \
  __builtin_choose_expr (__builtin_types_compatible_p (typeof (v), ft), \
			 ((tt)(v)), (void)0)

#define cast2unsigned(t, v) \
  __builtin_choose_expr (__builtin_types_compatible_p (typeof (v), t), \
			 ((unsigned t)(v)), (void)0)
#define cast2signed(t, v) \
  __builtin_choose_expr (__builtin_types_compatible_p \
			 (typeof (v), unsigned t), /**/ ((t)(v)), (void)0)
#define cast2unsigned_array(t, v) \
  __builtin_choose_expr (__builtin_types_compatible_p (typeof (v), t []), \
			 ((unsigned t *)(v)), (void)0)
#define cast2signed_array(t, v) \
  __builtin_choose_expr (__builtin_types_compatible_p \
			 (typeof (v), unsigned t []), /**/ ((t *)(v)), (void)0)
#else
#define GCCATTR_PRINTF(m, n)
#define GCCATTR_UNUSED
#define GCCATTR_NORETURN
#define GCCATTR_CONST

#define from_type(ft, v) (v)
#define checked_cast(tt, ft, v) ((tt)(v))

#define cast2unsigned(t, v) ((unsigned t)(v))
#define cast2unsigned_array(t, v) ((unsigned t)(v))
#define cast2signed(t, v) ((t)(v))
#define cast2signed_array(t, v) ((t)(v))
#endif

/* use this only to cast quoted strings in function calls */
#define CUS (const unsigned char *)

/* forward declarations */
typedef struct _Png4File Png4File;
typedef struct _BoundStr BoundStr;

#include "pxsup2dast_defs.hg"

enum { MiscError = 1, EOFIndicator, IndexError };


/****** Poor man's exception code ... (heavily inspired by cexcept). ******/

struct exc__state {
    struct exc__state * prev;
    jmp_buf env; };

struct {
    struct exc__state * last;
    char msgbuf[1024];
    int  buflen;
} EXC /* = { 0 }*/ ;

#define exc_try do { struct exc__state exc_s; int exc_type GCCATTR_UNUSED; \
    exc_s.prev = EXC.last; EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)

#define exc_ftry do { struct exc__state exc_s, *exc_p = EXC.last; \
    int exc_type GCCATTR_UNUSED; exc_s.prev = EXC.last; \
    EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)

#define exc_catch(t) else if (t == exc_type)

#define exc_end else __exc_throw(exc_type); EXC.last = exc_s.prev; } while (0)

#define exc_return for (EXC.last = exc_p;;) return

#define exc_fthrow for (EXC.last = exc_p;;) ex_throw

#define exc_catchall else
#define exc_endall EXC.last = exc_s.prev; } while (0)

static void __exc_throw(int type) /* protoadd GCCATTR_NORETURN */ {
    struct exc__state * exc_s;
    exc_s = EXC.last;
    EXC.last = EXC.last->prev;
    longjmp(exc_s->env, type); }

static void exc_throw(int type, const char * format, ...)
    /* protoadd GCCATTR_NORETURN */ {
    if (format != NULL) {
	va_list ap;
	unsigned int len;
	int err = errno;

	va_start(ap, format);
	len = vsnprintf(EXC.msgbuf, sizeof EXC.msgbuf, format, ap);
	va_end(ap);

	if (len >= sizeof EXC.msgbuf) {
	    len = sizeof EXC.msgbuf - 1;
	    EXC.msgbuf[len] = '\0'; }
	else {
	    if (format[strlen(format) - 1] == ':') {
		int l = snprintf(&EXC.msgbuf[len], sizeof EXC.msgbuf - len,
				  " %s.", strerror(err));
		if (l + len >= sizeof sizeof EXC.msgbuf) {
		    len = sizeof EXC.msgbuf - 1;
		    EXC.msgbuf[len] = '\0'; }
		else
		    len += l; }}
	EXC.buflen = len; }
    else {
	EXC.msgbuf[0] = '\0';
	EXC.buflen = 0; }

    __exc_throw(type); }

/****** end exception code block ******/


static eu8 * xxfread(FILE * stream, eu8 * ptr, size_t size) {
    size_t n = fread(ptr, size, 1, stream);
    if (n == 0) {
	if (ferror(stream))
	    exc_throw(MiscError, "fread failure:");
	exc_throw(EOFIndicator, NULL); }
    return ptr; }

static void xxfwrite(FILE * stream, const eu8 * ptr, size_t size) {
    size_t n = fwrite(ptr, size, 1, stream);
    if (n == 0) {
	if (ferror(stream))
	    exc_throw(MiscError, "fwrite failure:");
	exc_throw(MiscError, "fwrite failure:"); }}

#define xxfwriteCS(f, s) xxfwrite(f, CUS s, sizeof s - 1)

static void yuv2rgb(int y,   int cr,  int cb,
		    eu8 * r, eu8 * g, eu8 * b)  {
    int lr, lg, lb;

    /* from dvdauthor... */
    lr = (500 + 1164 * (y - 16) + 1596 * (cr - 128)              ) /1000;
    lg = (500 + 1164 * (y - 16) -  813 * (cr - 128) - 391 * (cb - 128)) / 1000;
    lb = (500 + 1164 * (y - 16)                    + 2018 * (cb - 128)) / 1000;

    *r = (lr < 0)? 0: (lr > 255)? 255: (eu8)lr;
    *g = (lg < 0)? 0: (lg > 255)? 255: (eu8)lg;
    *b = (lb < 0)? 0: (lb > 255)? 255: (eu8)lb;  }

static void rgb2yuv(eu8 r,   eu8   g,  eu8 b,
		    eu8 * y, eu8 * cr, eu8 * cb)  {
    /* int ly, lcr, lcb; */

    /* from dvdauthor... */
    *y  = ( 257 * r + 504 * g +  98 * b +  16500) / 1000;
    *cr = ( 439 * r - 368 * g -  71 * b + 128500) / 1000;
    *cb = (-148 * r - 291 * g + 439 * b + 128500) / 1000; }

/* the code above matches nicely with http://www.fourcc.org/fccyvrgb.php

 *  RGB to YUV Conversion

 * Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
 * Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
 * Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128

 * YUV to RGB Conversion

 * B = 1.164(Y - 16)                  + 2.018(U - 128)
 * G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
 * R = 1.164(Y - 16) + 1.596(V - 128)

*/


static FILE * xfopen(const char * filename, const char * mode) {
    FILE * fh = fopen(filename, mode);
    if (fh == NULL)
	exc_throw(MiscError, "fopen(\"%s\", \"%s\") failure:", filename, mode);
    return fh; }

static void xfseek0(FILE * stream, long offset) {
    if (fseek(stream, offset, SEEK_SET) < 0)
	exc_throw(MiscError, "fseek(stream, %ld, SEEK_SET) failure:",offset); }

static void xmkdir(const char * path, int mode) {
    if (mkdir(path, mode) < 0)
	exc_throw(MiscError, "mkdir(%s, 0%o) failure:", path, mode); }


static bool fexists(char * filename) {
    struct stat st;

    if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
	return true;
    return false; }

static bool dexists(char * filename) {
    struct stat st;

    if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode))
	return true;
    return false; }



static fu32 get_uint32_be(const eu8 * bytes)  {
    return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3]; }

static fu16 get_uint16_be(const eu8 * bytes)  {
    return (bytes[0] << 8) + bytes[1]; }

static fu32 get_uint32_le(const eu8 * bytes)  {
    return (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0]; }
#if 0  /* protoline */
static fu32 get_uint16_le(const eu8 * bytes)  {
    return (bytes[1] << 8) + bytes[0]; }
#endif  /* protoline */


static void set_uint32_be(eu8 * ptr, eu32 value) {
    ptr[0] = value>>24; ptr[1] = value>>16; ptr[2] = value>>8; ptr[3] =value; }
#if 0 /* protoline */
static void set_uint16_be(eu8 * ptr, eu32 value) {
    ptr[0] = value>>8; ptr[1] = value; }

static void set_uint32_le(eu8 * ptr, eu32 value) {
    ptr[3] = value>>24; ptr[2] = value>>16; ptr[1] = value>>8; ptr[0] =value; }
#endif  /* protoline */
static void set_uint16_le(eu8 * ptr, eu16 value) {
    ptr[1] = value>>8; ptr[0] =value; }

static void xxfwrite_uint32_be(FILE * fh, eu32 value) {
    eu8 buf[4];
    set_uint32_be(buf, value);
    xxfwrite(fh, buf, 4); }



static void ifopalette(const char * filename,
		       eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])  {
    eu8 buf[1024], r, g, b;
    fu32 offset, pgc;
    int i;
    FILE * fh;

    fh = xfopen(filename, "rb");
    if (memcmp(xxfread(fh, buf, 12), "DVDVIDEO-VTS", 12) != 0)
	exc_throw(MiscError,
		  "(IFO) file %s not of type DVDVIDEO-VTS.", filename);

    xfseek0(fh, 0xcc);
    offset = get_uint32_be(xxfread(fh, buf, 4));
    xfseek0(fh, offset * 0x800 + 12);
    pgc = offset * 0x800 + get_uint32_be(xxfread(fh, buf, 4));
    /* seek to palette */
    xfseek0(fh, pgc + 0xa4);
    xxfread(fh, buf, 16 * 4);
    for (i = 0; i < 16; i++) {
	eu8 * p = buf + i * 4 + 1;
	yuvpalette[i][0] =p[0]; yuvpalette[i][1] =p[1]; yuvpalette[i][2] =p[2];
	yuv2rgb(p[0], p[1], p[2], &r, &g, &b);
	rgbpalette[i][0] = r; rgbpalette[i][1] = g; rgbpalette[i][2] = b; } }


static void set2palettes(int value, eu8 * yuvpalpart, eu8 * rgbpalpart) {
    eu8 r, g, b, y, cr, cb;

    r = value >> 16; g = value >> 8; b = value;
    rgbpalpart[0] = r, rgbpalpart[1] = g,  rgbpalpart[2] = b;
    rgb2yuv(r, g, b, &y, &cr, &cb);
    yuvpalpart[0] = y, yuvpalpart[1] = cr, yuvpalpart[2] = cb; }


static void argpalette(const char * arg,
		       eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])  {
    unsigned int i;

    if (strlen(arg) != 20 || arg[6] != ',' || arg[13] != ',')
	exc_throw(MiscError, "Palette arg %s invalid.\n", arg);

    for (i = 0; i < 16; i++)
	set2palettes(i * 0x111111, yuvpalette[i], rgbpalette[i]);

    sscanf(arg, "%x", &i); /* "%x," ? */
    set2palettes(i, yuvpalette[1], rgbpalette[1]);
    sscanf(arg + 7, "%x", &i);
    set2palettes(i, yuvpalette[2], rgbpalette[2]);
    sscanf(arg + 14, "%x", &i);
    set2palettes(i, yuvpalette[3], rgbpalette[3]); }


/* typedef struct _Png4File Png4File; */
struct _Png4File {
    FILE * fh;
    int width;
    int hleft;
    int nibble;
    int bufpos;
    int chunklen;
    eu32 crc;
    eu32 adler;
    eu8 palettechunk[24];
    eu8 buffer[65536]; };

static void png4file_init(Png4File * self, eu8 palette[4][3]) {
    memcpy(self->palettechunk, "\0\0\0\x0c" "PLTE", 8);
    memcpy(self->palettechunk + 8, palette, 12);
    self->crc = 0 /*crc32(0, Z_NULL, 0)*/;
    self->crc = crc32(self->crc, self->palettechunk + 4, 16);
    set_uint32_be(self->palettechunk + 20, self->crc); }

static void png4file_open(Png4File * self,
			  const char * filename, int height, int width) {
    eu32 crc;
    self->fh = xfopen(filename, "wb");
    self->width = width;
    self->hleft = height;
    self->nibble = -1;

    xxfwrite(self->fh, CUS "\x89PNG\r\n\x1a\n" "\0\0\0\x0d", 12);

    memcpy(self->buffer, "IHDR", 4);
    set_uint32_be(self->buffer + 4, width);
    set_uint32_be(self->buffer + 8, height);
    memcpy(self->buffer + 12, "\004\003\0\0\0", 5);

    crc = crc32(0, self->buffer, 17);
    set_uint32_be(self->buffer + 17, crc);
    xxfwrite(self->fh, self->buffer, 21);

    xxfwrite(self->fh, self->palettechunk, sizeof self->palettechunk);

    /* XXX quick hack, first color transparent. */
    xxfwriteCS(self->fh, "\0\0\0\001" "tRNS" "\0" "\x40\xe6\xd8\x66");

    xxfwrite(self->fh, CUS "\0\0\0\0IDAT" "\x78\001", 10);
    self->buffer[0] = '\0';
    self->buffer[5] = '\0';
    self->bufpos = 6;
    self->chunklen = 2; /* 78 01, zlib header */
    self->crc = crc32(0, CUS "IDAT" "\x78\001", 6);
    self->adler = 1 /* adler32(0, Z_NULL, 0) */; }

static void png4file_addpixel(Png4File * self, eu8 pixel) {
    if (self->nibble < 0)
	self->nibble = (pixel << 4);
    else {
	self->buffer[self->bufpos++] = self->nibble | pixel;
	self->nibble = -1;
	if (self->bufpos == sizeof self->buffer - 4)
	    png4file_flush(self); }}

static void png4file_endrow(Png4File * self) {
    if (self->nibble >= 0) {
	self->buffer[self->bufpos++] = self->nibble;
	self->nibble = -1; }

    self->hleft--;
    if (self->hleft)
	self->buffer[self->bufpos++] = '\0'; }

static void png4file_close(Png4File * self) {
    eu8 adlerbuf[4];
    self->buffer[0] = 0x01;
    if (self->bufpos)
	png4file_flush(self);
    else {
	self->bufpos = 5;
	png4file_flush(self); }

    set_uint32_be(adlerbuf, self->adler);
    xxfwrite(self->fh, adlerbuf, 4);
    self->crc = crc32(self->crc, adlerbuf, 4);
    xxfwrite_uint32_be(self->fh, self->crc);
    xxfwriteCS(self->fh, "\0\0\0\0" "IEND" "\xae\x42\x60\x82");
    xfseek0(self->fh, 70);
    xxfwrite_uint32_be(self->fh, self->chunklen + 4 /* adler*/);
    fclose(self->fh);
    self->fh = NULL; }

static void png4file_flush(Png4File * self) {
    int l = self->bufpos - 5;
    self->chunklen += self->bufpos;
    set_uint16_le(self->buffer + 1, l);
    set_uint16_le(self->buffer + 3, l ^ 0xffff);
    xxfwrite(self->fh, self->buffer, self->bufpos);
    self->crc = crc32(self->crc, self->buffer, self->bufpos);
    self->adler = adler32(self->adler, self->buffer + 5, self->bufpos - 5);
    self->buffer[0] = '\0';
    self->bufpos = 5; }


static eu8 getnibble(eu8 ** data, int * nibble) {
    if (*nibble >= 0) {
	eu8 rv = *nibble & 0x0f;
	*nibble = -1;
	return rv; }
    /* else */
    *nibble = *(*data)++;
    return *nibble >> 4; }


static void getpixelline(eu8 ** data, int width, Png4File * picfile) {
    int nibble = -1;
    int col = 0;
    int number, cindex;
    /* Originally from gtkspu - this from the python implementation of this */

    while (1) {
	int bits = getnibble(data, &nibble);
	if ((bits & 0xc) != 0) {
	    /* have 4-bit code */
            number = (bits & 0xc) >> 2;
            cindex = bits & 0x3; }
        else {
            bits = (bits << 4) | getnibble(data, &nibble);
            if ((bits & 0xf0) != 0) {
                /* have 8-bit code */
                number = (bits & 0x3c) >> 2;
                cindex = bits & 0x3; }
            else {
                bits = (bits << 4) | getnibble(data, &nibble);
                if ((bits & 0xfc0) != 0) {
                    /* have 12-bit code */
                    number = (bits & 0xfc) >> 2;
                    cindex = bits & 0x3; }
		else {
                    /* have 16-bit code */
                    bits = (bits << 4) | getnibble(data, &nibble);
		    number = (bits & 0x3fc) >> 2;
                    cindex = bits & 0x3;

                    if (number == 0)
                        number = width; }}}

	/* printf("%d %d %d %d\n", number, col, width, cindex); */
	for (; number > 0 && col < width; number--, col++)
	    png4file_addpixel(picfile, cindex);

	if (col == width) {
	    png4file_endrow(picfile);
	    return; }}}

static void makebitmap(eu8 * data, int w, int h, int top, int bot,
		       char * filename, eu8 palette[4][3]) {
    eu8 * top_ibuf = data + top;
    eu8 * bot_ibuf = data + bot;
    int i;
    Png4File picfile;

    png4file_init(&picfile, palette); /* not bottleneck even re-doing this every time */
    png4file_open(&picfile, filename, h, w);
    for (i = 0; i < h / 2; i++) {
	getpixelline(&top_ibuf, w, &picfile);
	getpixelline(&bot_ibuf, w, &picfile); }
    png4file_close(&picfile); }


static char * pts2ts(fu32 pts, char * rvbuf, bool is_png_filename) {
    int h = pts / (3600 * 90000);
    int m = pts / (60 * 90000) % 60;
    int s = pts / 90000 % 60;
    int hs = pts / 900 % 100;

    if (is_png_filename)
	sprintf(rvbuf, "%02d+%02d+%02d.%02d.png", h, m, s, hs);
    else
	sprintf(rvbuf, "%02d:%02d:%02d.%02d", h, m, s, hs);

    return rvbuf; }

/* *********** */
struct _BoundStr {
    eu8 * p;
    int l; };

static void boundstr_init(BoundStr * bs, eu8 * p, int l) {
    bs->p = p;
    bs->l = l; }

static eu8 * boundstr_read(BoundStr * bs, int l) {
    eu8 * rp;
    if (l > bs->l)
	exc_throw(IndexError, "XXX IndexError %p.", bs);
    rp = bs->p;
    bs->p += l;
    bs->l -= l;
    return rp; }
/* *********** */


static void pxsubtitle(char * supfile, FILE * ofh, eu8 palette[16][3],
		       bool createpics, int delay_ms,
		       char * fnbuf, char * fnbuf_fp,
		       char * xnbuf, char * xnbuf_fp) {
    char  junk[32];
    char  sptsstr[32];
    eu8   data[65536];
    eu8 * ctrl;
    time_t pt = 0, ct;
    bool last = false;
    /*char  transparent[8]; */
    FILE * sfh = xfopen(supfile, "rb");
    if (memcmp(xxfread(sfh, data, 2), "SP", 2) != 0) {
	exc_throw(MiscError, "Syncword missing. XXX bailing out."); }

    /*sprintf(transparent,
      "%02x%02x%02x", palette[0][0], palette[0][1], palette[0][2]); */

    exc_try { while (1) {
	/* X.java reads 5 bytes of pts, SubPicture.java writes 4. With
	 * 4 bytes 47721 seconds (13.25 hours) can be handled.
	 * Later, bytes 1,2,3,4 (instead of 0,1,2,3) could be used.
	 * 256/90000 = 1/351 sec -- way better than required resolution. */
	eu32 pts = get_uint32_le(xxfread(sfh, data, 8));
	eu16 size = get_uint16_be(xxfread(sfh, data, 2));
	eu16 pack = get_uint16_be(xxfread(sfh, data, 2));
	eu32 endpts;
	xxfread(sfh, data, pack - 4);
	ctrl = data + pack - 4;
	xxfread(sfh, ctrl, size - pack);

	exc_try {
	    if (memcmp(xxfread(sfh, cast2unsigned_array(char, junk), 2),
		       "SP", 2) != 0)
		exc_throw(MiscError, "Syncword missing. XXX bailing out."); }
	exc_catch (EOFIndicator)
	    last = true;
	exc_end;
	{
	    BoundStr bs;
	    int  prev;
	    int x1 = -1, x2 = -1, y1 = -1, y2 = -1;
	    int top_field = -1, bot_field = -1;
	    int start = 0, end = 0;
	    int colcon_length;
	    eu8 this_palette[4][3];
	    boundstr_init(&bs, ctrl, size - pack);

	    prev = 0;
	    while (1) {
		int date = get_uint16_be(boundstr_read(&bs, 2));
		int next = get_uint16_be(boundstr_read(&bs, 2));

		while (1) {
		    eu8 * p;
		    eu8 cmd = boundstr_read(&bs, 1)[0];
		    int xpalette, i, n;
		    switch (cmd) {
		    case 0x00:		/* force display: */
			continue;
		    case 0x01:		/* start date (read above) */
			start = date;
			continue;
		    case 0x02:		/* stop date (read above) */
			end = date;
			continue;
		    case 0x03:		/* palette */
			xpalette = get_uint16_be(boundstr_read(&bs, 2));
			for (n = 0; n < 4; n++) {
			    i = (xpalette >> (n * 4) & 0x0f);
			    this_palette[n][0] = palette[i][0];
			    this_palette[n][1] = palette[i][1];
			    this_palette[n][2] = palette[i][2];
			}
			continue;
		    case 0x04:		/* alpha channel */
			/*alpha =*/ boundstr_read(&bs, 2);
			continue;
		    case 0x05:		/* coordinates */
			p = boundstr_read(&bs, 6);
			x1 = (p[0] << 4) + (p[1] >> 4);
			x2 = ((p[1] & 0xf) << 8) + p[2];
			y1 = (p[3] << 4) + (p[4] >> 4);
			y2 = ((p[4] & 0xf) << 8) + p[5];
			continue;
		    case 0x06:		/* rle offsets */
			top_field = get_uint16_be(boundstr_read(&bs, 2));
			bot_field = get_uint16_be(boundstr_read(&bs, 2));
			continue;
		    case 0x07:		/* */
			colcon_length = get_uint16_be(boundstr_read(&bs, 2)-2);
			boundstr_read(&bs, colcon_length);
			continue;
		    }
		    if (cmd == 0xff)	/* end command */
			break;
		    exc_throw(MiscError, "%d: Unknown control sequence", cmd);}
		if (prev == next)
		    break;
		prev = next; }

	    strcpy(xnbuf_fp, pts2ts(pts, fnbuf_fp, true));

	    if (delay_ms)
		pts += delay_ms * 90;

	    pts2ts(pts, sptsstr + 1, false);

	    if (pt != time(&ct)) {
		pt = ct;
		sptsstr[0] = '\r';
		write(1, sptsstr, strlen(sptsstr)); }

	    endpts = pts + end * 1000; /* ProjectX ! (other: 900, 1024) */

	    fprintf(ofh, "  <spu start=\"%s\" end=\"%s\" image=\"%s\""
		    " xoffset=\"%d\" yoffset=\"%d\" />\n",
		    sptsstr + 1, pts2ts(endpts, junk, false),
		    xnbuf, x1, y1);

	    if (createpics)
		makebitmap(data, x2 - x1 + 1, y2 - y1 + 1, top_field - 4,
			   bot_field - 4, fnbuf, this_palette);
	    if (last)
		exc_throw(EOFIndicator, NULL); }}}
    exc_catch (EOFIndicator) {
	write(1, sptsstr, strlen(sptsstr));
	return; }
    exc_end; }


static void usage(const char * pn) /* protoadd GCCATTR_NORETURN */ {
    exc_throw(MiscError, "\n"
	      "Usage: %s [--delay ms] <supfile> <ifofile>|<palette>" "\n"
	      "\n"
	      "\tExamples:" "\n"
	      "\n"
	      "\t ProjectX decoded recording.sup and recording.sup.IFO" "\n"
	      "\n"
	      "\t\t$ pxsup2dast recording.sup*" "\n"
	      "\n"
	      "\t Having test.sup and map.ifo" "\n"
	      "\n"
	      "\t\t$ pxsup2dast test.sup map.ifo" "\n"
	      "\n"
	      "\t No .IFO, so giving 3 colors (rgb components in hex)" "\n"
	      "\n"
	      "\t\t$ pxsup2dast titles.sup ff0000,00ff00,0000ff" "\n"
	      "\n"
	      "\t Trying to fix sync in recording" "\n"
	      "\n"
	      "\t\t$ pxsup2dast --delay 750 recording.sup*" "\n"
	      , pn); }


static bool samepalette(char * filename, eu8 palette[16][3]) {
    FILE * fh;
    int i;
    unsigned int r,g,b;

    if (! fexists(filename))
	return false;

    fh = xfopen(filename, "rb");
    for (i = 0; i < 16; i++)
	if (fscanf(fh, "%02x%02x%02x\n", &r, &g, &b) != 3 ||
	    r != palette[i][0] || g != palette[i][1] || b != palette[i][2]) {
	    fclose(fh);
	    return false; }
    fclose(fh);
    return true; }

static void mkdirname(const char * base, char ** fbp, char ** xbp)
{
    const char * p, *lastdotp = NULL;
    int l = 0, lastdotl = 0;

    char * fb = *fbp, *xb = *xbp;

    for (p = base; *p; p++) {
	switch (*p) {
	case '.': lastdotl = l; lastdotp = p; break;
	case '&': l += 4; break; /* & - &amp;  */
	case '"': l += 5; break; /* " - &quot; */
	case 047: l += 5; break; /* ' - &apos; */
	case '<': l += 3; break; /* < - &lt;   */
	case '>': l += 3; break; /* > - &gt;   */ }
	l += 1; }

    if (lastdotl == 0)
	lastdotl = l;

    if (l > 4000)
	exc_throw(MiscError, "Can "
		  "not manage filenames longer than 4000 characters.");

#define a_(x) *xb++ = x
    for (p = base; p < lastdotp; p++) {
	switch (*p) {
	case '&': a_('&'); a_('a'); a_('m'); a_('p'); a_(';'); break;
	case '"': a_('&'); a_('q'); a_('u'); a_('o'); a_('t'); a_(';'); break;
	case 047: a_('&'); a_('a'); a_('p'); a_('o'); a_('s'); a_(';'); break;
	case '<': a_('&'); a_('l'); a_('t'); a_(';'); break;
	case '>': a_('&'); a_('g'); a_('t'); a_(';'); break;
	default:  a_(*p); }
	*fb++ = *p;
    }
    *xb++ = *fb++ = '.';
    *xb++ = *fb++ = 'd';
    *xb++ = *fb++ = '/';

    *xbp = xb; *fbp = fb; }

int main(int argc, char ** argv)  {
    exc_try {
	int jc, i;
	eu8 yuvpalette[16][3], rgbpalette[16][3];
	char fnbuf[4096]; char * endfn;
	char xnbuf[4096]; char * endxn;

	bool createpics;
	FILE * fh;
	int delay_ms;

	write(1, "\n", 1);
	if (sizeof (char) != 1 || sizeof (int) < 2) /* very unlikely */
	    exc_throw(MiscError, "Incompatible variable sizes.");

	delay_ms = 0;
	if (argc > 3 && strcmp(argv[1], "--delay") == 0) {
	    delay_ms = atoi(argv[2]);
	    if (delay_ms != 0)
		argc-= 2; argv+= 2; }

	if (argc != 3)
	    usage(argv[0]);

	endfn = fnbuf; endxn = xnbuf;
	mkdirname(argv[1], &endfn, &endxn);

	if (!dexists(fnbuf))
	    xmkdir(fnbuf, 0755);

	if (fexists(argv[2]))
	    ifopalette(argv[2], yuvpalette, rgbpalette);
	else
	    argpalette(argv[2], yuvpalette, rgbpalette);

	strcpy(endfn, "palette.ycrcb");
	if (samepalette(fnbuf, yuvpalette)) {
	    createpics = false;
	    printf("Found palette.yuv having our palette information...\n");
	    printf("...Skipping image files, Writing spumux.tmp.\n"); }
	else {
	    createpics = true;
	    printf("Writing image files and spumux.tmp.\n"); }

	strcpy(endfn, "spumux.tmp");
	fh = xfopen(fnbuf, "wb");

	xxfwriteCS(fh, "<subpictures>\n <stream>\n");
	pxsubtitle(argv[1], fh, rgbpalette, createpics, delay_ms,
		   fnbuf, endfn, xnbuf, endxn);

	write(1, "\n", 1);
	xxfwriteCS(fh, " </stream>\n</subpictures>\n");
	fclose(fh);

	if (createpics) {
	    FILE * yuvfh, *rgbfh;
	    printf("Writing palette.ycrcb and palette.rgb.\n");
	    strcpy(endfn, "palette.ycrcb");
	    yuvfh = xfopen(fnbuf, "wb");
	    strcpy(endfn, "palette.rgb");
	    rgbfh = xfopen(fnbuf, "wb");
	    for (i = 0; i < 16; i++) {
		fprintf(yuvfh, "%02x%02x%02x\n",
			yuvpalette[i][0], yuvpalette[i][1], yuvpalette[i][2]);
		fprintf(rgbfh, "%02x%02x%02x\n",
			rgbpalette[i][0], rgbpalette[i][1], rgbpalette[i][2]);}
	    fclose(yuvfh);
	    fclose(rgbfh); }

	{   char buf[4096];
	    printf("Renaming spumux.tmp to spumux.xml.\n");
	    strcpy(endfn, "spumux.tmp");
	    i = strlen(fnbuf);
	    memcpy(buf, fnbuf, i);
	    strcpy(&buf[i - 3], "xml");
	    unlink(buf);
	    rename(fnbuf, buf);
	    jc = 0; }
	endfn[0] = '\0';
	printf("Output files reside in %s\n", fnbuf);
	printf("All done.\n"); }

    exc_catchall {
	write(2, EXC.msgbuf, EXC.buflen); write(2, "\n", 1);
	exit(1);
    }
    exc_endall;

    return 0; }

/*
 * Local variables:
 * mode: c
 * c-file-style: "stroustrup"
 * tab-width: 8
 * compile-command: "sh pxsup2dast.c"
 * End:
 */


--- NEW FILE pxsup2dast.spec ---
Name:           pxsup2dast
Version:        20120704
Release:        3%{?dist}
Summary:        Project X to dvdauthor subtitle converter

License:        GPLv2
URL:            http://www.guru-group.fi/~too/sw/m2vmp2cut/
Source0:        http://www.guru-group.fi/~too/sw/m2vmp2cut/pxsup2dast.c

BuildRequires:  perl
BuildRequires:  zlib-devel

%description
pxsup2dast converts Project X's sup subtitles to XML subtitle files
for use with dvdauthor.


%prep
%setup -c -T
perl -pe 's/-O2/\$RPM_OPT_FLAGS \$RPM_LD_FLAGS/' %{SOURCE0} > %{name}.c


%build
sh %{name}.c


%install
install -Dpm 755 pxsup2dast $RPM_BUILD_ROOT%{_bindir}/pxsup2dast


%files
%{_bindir}/pxsup2dast


%changelog
* Tue May 14 2013 Martin Gansser <martinkg at fedoraproject.org> - 20120704-3
- rebuild with recent source file

* Mon May 13 2013 Martin Gansser <martinkg at fedoraproject.org> - 20120704-2
- rebuild

* Thu Jul 4 2012 Ville Skyttä <ville.skytta at iki.fi> - 20120704-1
- Update to 20120704.

* Sun Aug 29 2010 Ville Skyttä <ville.skytta at iki.fi> - 20100827-1
- Update to 20100827.

* Sun Jan 10 2010 Ville Skyttä <ville.skytta at iki.fi> - 20090809-1
- Update to 20090809, POSIX 2008 build fix applied upstream.

* Tue Aug  4 2009 Ville Skyttä <ville.skytta at iki.fi> - 20090111-2
- Fix POSIX 2008 build.

* Thu Feb  5 2009 Ville Skyttä <ville.skytta at iki.fi> - 20090111-1
- 2009-01-11.

* Fri May 25 2007 Ville Skyttä <ville.skytta at iki.fi> - 20070305-1
- 2007-03-05.

* Sat Sep 30 2006 Ville Skyttä <ville.skytta at iki.fi> - 20060125-2
- Rebuild.

* Thu Aug 17 2006 Ville Skyttä <ville.skytta at iki.fi> - 20060125-1
- First build.


More information about the rpmfusion-commits mailing list