|
Packit |
78deda |
/** rlatopam.c - read Alias/Wavefront RLA or RPF file
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 2005 Matte World Digital
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Author: Simon Walton
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
**/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <string.h>
|
|
Packit |
78deda |
#include <errno.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "pam.h"
|
|
Packit |
78deda |
#include "rla.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static int * offsets;
|
|
Packit |
78deda |
static bool is_float;
|
|
Packit |
78deda |
static bool has_matte;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned int depth;
|
|
Packit |
78deda |
static unsigned int width;
|
|
Packit |
78deda |
static unsigned int height;
|
|
Packit |
78deda |
static unsigned int chanBits;
|
|
Packit |
78deda |
static short storageType;
|
|
Packit |
78deda |
static struct pam outpam;
|
|
Packit |
78deda |
static unsigned int numChan;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommandLine(int const argc,
|
|
Packit |
78deda |
char ** const argv,
|
|
Packit |
78deda |
const char ** const inputFileNameP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 1)
|
|
Packit |
78deda |
*inputFileNameP = "-";
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
*inputFileNameP = argv[1];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 > 1)
|
|
Packit |
78deda |
pm_error("There is at most one argument - input file name. "
|
|
Packit |
78deda |
"You specified %u", argc-1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static bool littleEndian;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
determineEndianness(void) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
union {
|
|
Packit |
78deda |
unsigned char bytes[2];
|
|
Packit |
78deda |
unsigned short number;
|
|
Packit |
78deda |
} u;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
u.number = 1;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
littleEndian = (u.bytes[0] == 1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned short
|
|
Packit |
78deda |
byteswap(unsigned short const input) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return (input << 8) | (input >> 8);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
read_header(FILE * const ifP,
|
|
Packit |
78deda |
rlahdr * const hdrP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rlahdr hdr;
|
|
Packit |
78deda |
size_t bytesRead;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
fseek (ifP, 0, SEEK_SET);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Here we have a hack. The bytes in the file are almost in the
|
|
Packit |
78deda |
same format as the compiler stores 'hdr' in memory. The only
|
|
Packit |
78deda |
difference is that the compiler may store the integer values
|
|
Packit |
78deda |
in the obscene little-endian format. So we just read the whole
|
|
Packit |
78deda |
header into 'hdr' as if it were the right format, and then
|
|
Packit |
78deda |
correct the integer values by swapping their bytes.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
The _right_ way to do this is to read the file one field at a time,
|
|
Packit |
78deda |
using pm_readbigshort() where appropriate.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bytesRead = fread(&hdr, sizeof hdr, 1, ifP);
|
|
Packit |
78deda |
if (bytesRead != 1)
|
|
Packit |
78deda |
pm_error("Unexpected EOF on input file.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (littleEndian) {
|
|
Packit |
78deda |
hdr.window.left = byteswap(hdr.window.left);
|
|
Packit |
78deda |
hdr.window.right = byteswap(hdr.window.right);
|
|
Packit |
78deda |
hdr.window.bottom = byteswap(hdr.window.bottom);
|
|
Packit |
78deda |
hdr.window.top = byteswap(hdr.window.top);
|
|
Packit |
78deda |
hdr.active_window.left = byteswap(hdr.active_window.left);
|
|
Packit |
78deda |
hdr.active_window.right = byteswap(hdr.active_window.right);
|
|
Packit |
78deda |
hdr.active_window.bottom = byteswap(hdr.active_window.bottom);
|
|
Packit |
78deda |
hdr.active_window.top = byteswap(hdr.active_window.top);
|
|
Packit |
78deda |
hdr.storage_type = byteswap(hdr.storage_type);
|
|
Packit |
78deda |
hdr.num_chan = byteswap(hdr.num_chan);
|
|
Packit |
78deda |
hdr.num_matte = byteswap(hdr.num_matte);
|
|
Packit |
78deda |
hdr.revision = byteswap(hdr.revision);
|
|
Packit |
78deda |
hdr.chan_bits = byteswap(hdr.chan_bits);
|
|
Packit |
78deda |
hdr.matte_type = byteswap(hdr.matte_type);
|
|
Packit |
78deda |
hdr.matte_bits = byteswap(hdr.matte_bits);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (hdr.revision != 0xfffe && hdr.revision != 0xfffd)
|
|
Packit |
78deda |
pm_error("Invalid file header. \"revision\" field should contain "
|
|
Packit |
78deda |
"0xfffe or 0xfffd, but contains 0x%04x", hdr.revision);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*hdrP = hdr;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
decodeFP(unsigned char * const in,
|
|
Packit |
78deda |
unsigned char * const out,
|
|
Packit |
78deda |
int const width,
|
|
Packit |
78deda |
int const stride) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int x;
|
|
Packit |
78deda |
unsigned char * inputCursor;
|
|
Packit |
78deda |
unsigned char * outputCursor;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
inputCursor = &in[0];
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (x = 0; x < width; ++x) {
|
|
Packit |
78deda |
union {char bytes [4]; float fv;} fi;
|
|
Packit |
78deda |
unsigned short val;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (littleEndian) {
|
|
Packit |
78deda |
fi.bytes [3] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [2] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [1] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [0] = *inputCursor++;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
fi.bytes [0] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [1] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [2] = *inputCursor++;
|
|
Packit |
78deda |
fi.bytes [3] = *inputCursor++;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
val = fi.fv > 1 ? 65535 : (fi.fv < 0 ? 0 :
|
|
Packit |
78deda |
(unsigned short) (65535 * fi.fv + .5));
|
|
Packit |
78deda |
outputCursor[0] = val >> 8; outputCursor[1] = val & 0xff;
|
|
Packit |
78deda |
outputCursor += stride;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned char *
|
|
Packit |
78deda |
decode(unsigned char * const input,
|
|
Packit |
78deda |
unsigned char * const output,
|
|
Packit |
78deda |
int const xFile,
|
|
Packit |
78deda |
int const xImage,
|
|
Packit |
78deda |
int const stride) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int x;
|
|
Packit |
78deda |
unsigned int bytes;
|
|
Packit |
78deda |
unsigned int useX;
|
|
Packit |
78deda |
unsigned char * inputCursor;
|
|
Packit |
78deda |
unsigned char * outputCursor;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
inputCursor = &input[0];
|
|
Packit |
78deda |
outputCursor = &output[0];
|
|
Packit |
78deda |
x = xFile;
|
|
Packit |
78deda |
bytes = 0;
|
|
Packit |
78deda |
useX = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
while (x > 0) {
|
|
Packit |
78deda |
int count;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
count = *(signed char *)inputCursor++;
|
|
Packit |
78deda |
++bytes;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (count >= 0) {
|
|
Packit |
78deda |
/* Repeat pixel value (count + 1) times. */
|
|
Packit |
78deda |
while (count-- >= 0) {
|
|
Packit |
78deda |
if (useX < xImage) {
|
|
Packit |
78deda |
*outputCursor = *inputCursor;
|
|
Packit |
78deda |
outputCursor += stride;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
--x;
|
|
Packit |
78deda |
++useX;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
++inputCursor;
|
|
Packit |
78deda |
++bytes;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* Copy (-count) unencoded values. */
|
|
Packit |
78deda |
for (count = -count; count > 0; --count) {
|
|
Packit |
78deda |
if (useX < xImage) {
|
|
Packit |
78deda |
*outputCursor = *inputCursor;
|
|
Packit |
78deda |
outputCursor += stride;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
++inputCursor;
|
|
Packit |
78deda |
++bytes;
|
|
Packit |
78deda |
--x;
|
|
Packit |
78deda |
++useX;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return inputCursor;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
decode_row(FILE * const ifP,
|
|
Packit |
78deda |
int const row,
|
|
Packit |
78deda |
unsigned char * const rb) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned char * read_buffer = NULL;
|
|
Packit |
78deda |
unsigned int chan;
|
|
Packit |
78deda |
int rc;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!read_buffer) {
|
|
Packit |
78deda |
MALLOCARRAY(read_buffer, width * 4);
|
|
Packit |
78deda |
if (read_buffer == 0)
|
|
Packit |
78deda |
pm_error("Unable to get memory for read_buffer");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rc = fseek (ifP, offsets [height - row - 1], SEEK_SET);
|
|
Packit |
78deda |
if (rc != 0)
|
|
Packit |
78deda |
pm_error("fseek() failed with errno %d (%s)",
|
|
Packit |
78deda |
errno, strerror(errno));
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (chan = 0; chan < outpam.depth; ++chan) {
|
|
Packit |
78deda |
unsigned short length;
|
|
Packit |
78deda |
size_t bytesRead;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_readbigshortu(ifP, &length);
|
|
Packit |
78deda |
if (length > width * 4)
|
|
Packit |
78deda |
pm_error("Line too long - row %u, channel %u", row, chan);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bytesRead = fread(read_buffer, 1, length, ifP);
|
|
Packit |
78deda |
if (bytesRead != length)
|
|
Packit |
78deda |
pm_error("EOF encountered unexpectedly");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (is_float)
|
|
Packit |
78deda |
decodeFP(read_buffer, rb + chan * 2, width, outpam.depth * 2);
|
|
Packit |
78deda |
else if (depth > 8) {
|
|
Packit |
78deda |
/* Hi byte */
|
|
Packit |
78deda |
unsigned char * const newpos =
|
|
Packit |
78deda |
decode(read_buffer, rb + chan * 2, width, width,
|
|
Packit |
78deda |
outpam.depth * 2);
|
|
Packit |
78deda |
/* Lo byte */
|
|
Packit |
78deda |
decode(newpos, rb + chan * 2 + 1, width, width,
|
|
Packit |
78deda |
outpam.depth * 2);
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
decode(read_buffer, rb + chan, width, width, outpam.depth);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
getHeaderInfo(FILE * const ifP,
|
|
Packit |
78deda |
unsigned int * const widthP,
|
|
Packit |
78deda |
unsigned int * const heightP,
|
|
Packit |
78deda |
unsigned int * const depthP,
|
|
Packit |
78deda |
bool * const hasMatteP,
|
|
Packit |
78deda |
unsigned int * const chanBitsP,
|
|
Packit |
78deda |
short * const storageType) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
rlahdr hdr;
|
|
Packit |
78deda |
int width, height;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
read_header(ifP, &hdr);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
height = hdr.active_window.top - hdr.active_window.bottom + 1;
|
|
Packit |
78deda |
width = hdr.active_window.right - hdr.active_window.left + 1;
|
|
Packit |
78deda |
if (width <=0)
|
|
Packit |
78deda |
pm_error("Invalid input image. It says its width isn't positive");
|
|
Packit |
78deda |
if (height <=0)
|
|
Packit |
78deda |
pm_error("Invalid input image. It says its height isn't positive");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*widthP = width;
|
|
Packit |
78deda |
*heightP = height;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (hdr.num_chan != 1 && hdr.num_chan != 3)
|
|
Packit |
78deda |
pm_error ("Input image has bad number of channels: %d. "
|
|
Packit |
78deda |
"Should be 1 or 3.",
|
|
Packit |
78deda |
hdr.num_chan);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*depthP = hdr.chan_bits <= 8 ? 8 : 16;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
*hasMatteP = (hdr.num_matte > 0);
|
|
Packit |
78deda |
*chanBitsP = hdr.chan_bits;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readOffsetArray(FILE * const ifP,
|
|
Packit |
78deda |
int ** const offsetsP,
|
|
Packit |
78deda |
unsigned int const height) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int * offsets;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY(offsets, height);
|
|
Packit |
78deda |
if (offsets == NULL)
|
|
Packit |
78deda |
pm_error("Unable to allocate memory for the offsets array");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (row = 0; row < height; ++row) {
|
|
Packit |
78deda |
long l;
|
|
Packit |
78deda |
pm_readbiglong(ifP, &l);
|
|
Packit |
78deda |
offsets[row] = l;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
*offsetsP = offsets;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
destroyOffsetArray(int * const offsets) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
free(offsets);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
readAndWriteRaster(FILE * const ifP,
|
|
Packit |
78deda |
const struct pam * const outpamP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned char * rowBuffer;
|
|
Packit |
78deda |
tuple * tuplerow;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Hold one row of all image planes */
|
|
Packit |
78deda |
rowBuffer = calloc(1, width * outpamP->depth * 4);
|
|
Packit |
78deda |
if (rowBuffer == NULL)
|
|
Packit |
78deda |
pm_error("Unable to allocate memor for row buffer.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
tuplerow = pnm_allocpamrow(outpamP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (row = 0; row < height; ++row) {
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
unsigned char * rbP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
decode_row(ifP, row, rowBuffer);
|
|
Packit |
78deda |
for (col = 0, rbP = rowBuffer; col < width; ++col) {
|
|
Packit |
78deda |
unsigned int chan;
|
|
Packit |
78deda |
for (chan = 0; chan < outpamP->depth; ++chan) {
|
|
Packit |
78deda |
if (depth > 8) {
|
|
Packit |
78deda |
tuplerow[col][chan] = 256 * rbP[0] + rbP[1];
|
|
Packit |
78deda |
rbP += 2;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
tuplerow[col][chan] = *rbP;
|
|
Packit |
78deda |
rbP += 1;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pnm_writepamrow(outpamP, tuplerow);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pnm_freepamrow(tuplerow);
|
|
Packit |
78deda |
free(rowBuffer);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc,
|
|
Packit |
78deda |
char * argv[]) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
const char * inputFileName;
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_init(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
determineEndianness();
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommandLine(argc, argv, &inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr_seekable(inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
getHeaderInfo(ifP, &width, &height, &depth, &has_matte,
|
|
Packit |
78deda |
&chanBits, &storageType);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
outpam.size = outpam.len = sizeof (struct pam);
|
|
Packit |
78deda |
outpam.file = stdout;
|
|
Packit |
78deda |
outpam.format = PAM_FORMAT;
|
|
Packit |
78deda |
outpam.height = height;
|
|
Packit |
78deda |
outpam.width = width;
|
|
Packit |
78deda |
outpam.depth = numChan + (has_matte ? 1 : 0);
|
|
Packit |
78deda |
outpam.maxval = (1 << (chanBits > 16 ?
|
|
Packit |
78deda |
(9 + (chanBits - 1) % 8)
|
|
Packit |
78deda |
/* Take top 2 of 3 or 4 bytes */
|
|
Packit |
78deda |
: chanBits)) - 1;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Most apps seem to assume 32 bit integer is really floating point */
|
|
Packit |
78deda |
if (chanBits == 32 || storageType == 4) {
|
|
Packit |
78deda |
is_float = TRUE;
|
|
Packit |
78deda |
outpam.maxval = 65535;
|
|
Packit |
78deda |
depth = 16;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
outpam.bytes_per_sample = depth / 8;
|
|
Packit |
78deda |
strcpy(outpam.tuple_type, (numChan == 3 ? "RGB" : "GRAYSCALE"));
|
|
Packit |
78deda |
if (has_matte)
|
|
Packit |
78deda |
strcat(outpam.tuple_type, "A");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readOffsetArray(ifP, &offsets, height);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_writepaminit(&outpam);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
readAndWriteRaster(ifP, &outpam);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
destroyOffsetArray(offsets);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|