#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ByteOrder.h>
#include <Catalog.h>
#include <File.h>
#include <TranslatorFormats.h>
#include <StorageDefs.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "tgainfo"
#define max(x,y) ((x > y) ? x : y)
#define DATA_BUFFER_SIZE 64
struct TGAFileHeader {
uint8 idlength;
uint8 colormaptype;
uint8 imagetype;
};
#define TGA_NO_COLORMAP 0
#define TGA_COLORMAP 1
#define TGA_NO_IMAGE_DATA 0
#define TGA_NOCOMP_COLORMAP 1
#define TGA_NOCOMP_TRUECOLOR 2
#define TGA_NOCOMP_BW 3
#define TGA_RLE_COLORMAP 9
#define TGA_RLE_TRUECOLOR 10
#define TGA_RLE_BW 11
struct TGAColorMapSpec {
uint16 firstentry;
uint16 length;
uint8 entrysize;
};
struct TGAImageSpec {
uint16 xorigin;
uint16 yorigin;
uint16 width;
uint16 height;
uint8 depth;
uint8 descriptor;
};
#define TGA_ORIGIN_VERT_BIT 0x20
#define TGA_ORIGIN_BOTTOM 0
#define TGA_ORIGIN_TOP 1
#define TGA_ORIGIN_HORZ_BIT 0x10
#define TGA_ORIGIN_LEFT 0
#define TGA_ORIGIN_RIGHT 1
#define TGA_DESC_BITS76 0xc0
#define TGA_DESC_ALPHABITS 0x0f
#define TGA_HEADERS_SIZE 18
#define TGA_FTR_LEN 26
#define TGA_EXT_LEN 495
#define LINE_LEN 82
const char *
colormaptype(uint8 n)
{
switch (n) {
case 0: return B_TRANSLATE("No colormap");
case 1: return B_TRANSLATE("colormap");
}
return "unknown";
}
const char *
imagetype(uint8 n)
{
switch (n) {
case 0: return B_TRANSLATE("No Image Data");
case 1: return B_TRANSLATE("colormap");
case 2: return B_TRANSLATE("true color");
case 3: return B_TRANSLATE("grayscale");
case 9: return B_TRANSLATE("RLE colormap");
case 10: return B_TRANSLATE("RLE true color");
case 11: return B_TRANSLATE("RLE grayscale");
default: break;
}
return B_TRANSLATE("unknown");
}
uint16
tga_uint16(char *buffer, int32 offset)
{
return B_LENDIAN_TO_HOST_INT16(*(reinterpret_cast<uint16 *>(buffer + offset)));
}
uint32
tga_uint32(char *buffer, int32 offset)
{
return B_LENDIAN_TO_HOST_INT32(*(reinterpret_cast<uint32 *>(buffer + offset)));
}
void
print_tga_info(BFile &file)
{
uint8 buf[TGA_HEADERS_SIZE];
ssize_t size = TGA_HEADERS_SIZE;
if (size > 0 && file.Read(buf, size) != size) {
printf(B_TRANSLATE("Error: unable to read all TGA headers\n"));
return;
}
TGAFileHeader fh;
fh.idlength = buf[0];
fh.colormaptype = buf[1];
fh.imagetype = buf[2];
printf(B_TRANSLATE("\nFile Header:\n"));
printf(B_TRANSLATE(" id length: %d\n"), static_cast<int>(fh.idlength));
printf(B_TRANSLATE("colormap type: %d (%s)\n"),
static_cast<int>(fh.colormaptype),
static_cast<const char *>(colormaptype(fh.colormaptype)));
printf(B_TRANSLATE(" image type: %d (%s)\n"),
static_cast<int>(fh.imagetype),
static_cast<const char *>(imagetype(fh.imagetype)));
TGAColorMapSpec mapspec;
mapspec.firstentry = tga_uint16(reinterpret_cast<char *>(buf), 3);
mapspec.length = tga_uint16(reinterpret_cast<char *>(buf), 5);
mapspec.entrysize = buf[7];
printf(B_TRANSLATE("\nColormap Spec:\n"));
printf(B_TRANSLATE("first entry: %d\n"),
static_cast<int>(mapspec.firstentry));
printf(B_TRANSLATE(" length: %d\n"),
static_cast<int>(mapspec.length));
printf(B_TRANSLATE(" entry size: %d\n"),
static_cast<int>(mapspec.entrysize));
TGAImageSpec imagespec;
imagespec.xorigin = tga_uint16(reinterpret_cast<char *>(buf), 8);
imagespec.yorigin = tga_uint16(reinterpret_cast<char *>(buf), 10);
imagespec.width = tga_uint16(reinterpret_cast<char *>(buf), 12);
imagespec.height = tga_uint16(reinterpret_cast<char *>(buf), 14);
imagespec.depth = buf[16];
imagespec.descriptor = buf[17];
printf(B_TRANSLATE("\nImage Spec:\n"));
printf(B_TRANSLATE(" x origin: %d\n"),
static_cast<int>(imagespec.xorigin));
printf(B_TRANSLATE(" y origin: %d\n"),
static_cast<int>(imagespec.yorigin));
printf(B_TRANSLATE(" width: %d\n"),
static_cast<int>(imagespec.width));
printf(B_TRANSLATE(" height: %d\n"),
static_cast<int>(imagespec.height));
printf(B_TRANSLATE(" depth: %d\n"),
static_cast<int>(imagespec.depth));
printf(B_TRANSLATE("descriptor: 0x%.2x\n"),
static_cast<int>(imagespec.descriptor));
printf(B_TRANSLATE("\talpha (attr): %d\n"),
static_cast<int>(imagespec.descriptor & TGA_DESC_ALPHABITS));
if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
if (imagespec.descriptor & TGA_ORIGIN_HORZ_BIT)
printf(B_TRANSLATE("\t origin: %d (%s %s)\n"),
static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("top"),
static_cast<const char *>("right"));
else
printf(B_TRANSLATE("\t origin: %d (%s %s)\n"),
static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("top"),
static_cast<const char *>("left"));
else
if (imagespec.descriptor & TGA_ORIGIN_HORZ_BIT)
printf(B_TRANSLATE("\t origin: %d (%s %s)\n"),
static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("bottom"),
static_cast<const char *>("right"));
else
printf(B_TRANSLATE("\t origin: %d (%s %s)\n"),
static_cast<int>(imagespec.descriptor & (TGA_ORIGIN_VERT_BIT
| TGA_ORIGIN_HORZ_BIT)), static_cast<const char *>("bottom"),
static_cast<const char *>("left"));
printf(B_TRANSLATE("\t bits 7 & 6: %d\n"),
static_cast<int>(imagespec.descriptor & TGA_DESC_BITS76));
off_t filesize = 0;
if (file.GetSize(&filesize) == B_OK) {
char tgafooter[TGA_FTR_LEN + 1] = { 0 };
if (file.ReadAt(filesize - TGA_FTR_LEN, tgafooter, TGA_FTR_LEN) == TGA_FTR_LEN) {
if (strcmp(tgafooter + 8, "TRUEVISION-XFILE.") == 0) {
uint32 extoffset = 0, devoffset = 0;
extoffset = tga_uint32(tgafooter, 0);
devoffset = tga_uint32(tgafooter, 4);
printf(B_TRANSLATE("\nTGA Footer:\n"));
printf(B_TRANSLATE("extension offset: 0x%.8lx (%ld)\n"),
static_cast<long int>(extoffset),
static_cast<long int>(extoffset));
printf(B_TRANSLATE("developer offset: 0x%.8lx (%ld)\n"),
static_cast<long int>(devoffset),
static_cast<long int>(devoffset));
printf(B_TRANSLATE("signature: %s\n"), tgafooter + 8);
if (extoffset) {
char extbuf[TGA_EXT_LEN];
if (file.ReadAt(extoffset, extbuf, TGA_EXT_LEN) == TGA_EXT_LEN) {
printf(B_TRANSLATE("\nExtension Area:\n"));
char strbuffer[LINE_LEN];
uint16 extsize = tga_uint16(extbuf, 0);
if (extsize < TGA_EXT_LEN) {
printf(B_TRANSLATE("\nError: extension "
"area is too small (%d)\n"), extsize);
return;
}
printf(B_TRANSLATE("size: %d\n"), extsize);
memset(strbuffer, 0, LINE_LEN);
strncpy(strbuffer, extbuf + 2, 41);
printf("author: \"%s\"\n", strbuffer);
printf(B_TRANSLATE("comments:\n"));
for (int32 i = 0; i < 4; i++) {
memset(strbuffer, 0, LINE_LEN);
strcpy(strbuffer, extbuf + 43 + (i * 81));
printf(B_TRANSLATE("\tline %ld: \"%s\"\n"),
static_cast<long int>(i + 1),
static_cast<const char *>(strbuffer));
}
printf(B_TRANSLATE("date/time (yyyy-mm-dd hh:mm:ss): "
"%.4d-%.2d-%.2d %.2d:%.2d:%.2d\n"),
tga_uint16(extbuf, 367), tga_uint16(extbuf, 369),
tga_uint16(extbuf, 371), tga_uint16(extbuf, 373),
tga_uint16(extbuf, 375), tga_uint16(extbuf, 377));
memset(strbuffer, 0, LINE_LEN);
strncpy(strbuffer, extbuf + 379, 41);
printf(B_TRANSLATE("job name: \"%s\"\n"), strbuffer);
printf(B_TRANSLATE("job time (hh:mm:ss): "
"%.2d:%.2d:%.2d\n"), tga_uint16(extbuf, 420),
tga_uint16(extbuf, 422), tga_uint16(extbuf, 424));
memset(strbuffer, 0, LINE_LEN);
strncpy(strbuffer, extbuf + 426, 41);
printf(B_TRANSLATE("software id: \"%s\"\n"),
strbuffer);
char strver[] = "[null]";
if (extbuf[469] != '\0') {
strver[0] = extbuf[469];
strver[1] = '\0';
}
printf(B_TRANSLATE("software version, letter: %d, "
"%s\n"), tga_uint16(extbuf, 467), strver);
printf(B_TRANSLATE("key color (A,R,G,B): %d, %d, %d, "
"%d\n"), extbuf[470], extbuf[471], extbuf[472],
extbuf[473]);
printf(B_TRANSLATE("pixel aspect ratio: %d / %d\n"),
tga_uint16(extbuf, 474), tga_uint16(extbuf, 476));
printf(B_TRANSLATE("gamma value: %d / %d\n"),
tga_uint16(extbuf, 478), tga_uint16(extbuf, 480));
printf(B_TRANSLATE("color correction offset: 0x%.8lx "
"(%ld)\n"), tga_uint32(extbuf, 482),
tga_uint32(extbuf, 482));
printf(B_TRANSLATE("postage stamp offset: 0x%.8lx "
"(%ld)\n"), tga_uint32(extbuf, 486),
tga_uint32(extbuf, 486));
printf(B_TRANSLATE("scan line offset: 0x%.8lx "
"(%ld)\n"), tga_uint32(extbuf, 490),
tga_uint32(extbuf, 490));
const char *strattrtype = NULL;
uint8 attrtype = extbuf[494];
switch (attrtype) {
case 0: strattrtype
= B_TRANSLATE("no alpha"); break;
case 1: strattrtype
= B_TRANSLATE("undefined, ignore"); break;
case 2: strattrtype
= B_TRANSLATE("undefined, retain"); break;
case 3: strattrtype
= B_TRANSLATE("alpha"); break;
case 4: strattrtype
= B_TRANSLATE("pre-multiplied alpha"); break;
default:
if (attrtype > 4 && attrtype < 128)
strattrtype = B_TRANSLATE("reserved");
else
strattrtype = B_TRANSLATE("unassigned");
break;
}
printf(B_TRANSLATE("attributes type: %d (%s)\n"),
attrtype, strattrtype);
} else
printf(B_TRANSLATE("\nError: Unable to read entire "
"extension area\n"));
}
} else
printf(B_TRANSLATE("\nTGA footer not found\n"));
} else
printf(B_TRANSLATE("\nError: Unable to read TGA footer "
"section\n"));
} else
printf(B_TRANSLATE("\nError: Unable to get file size\n"));
}
int
main(int argc, char **argv)
{
printf("\n");
if (argc == 1) {
printf(B_TRANSLATE("tgainfo - reports information about a TGA image file\n"));
printf(B_TRANSLATE("\nUsage:\n"));
printf(B_TRANSLATE("tgainfo filename.tga\n"));
}
else {
BFile file;
for (int32 i = 1; i < argc; i++) {
if (file.SetTo(argv[i], B_READ_ONLY) != B_OK)
printf(B_TRANSLATE("\nError opening %s\n"), argv[i]);
else {
printf(B_TRANSLATE("\nTGA image information for: %s\n"), argv[i]);
print_tga_info(file);
}
}
}
printf("\n");
return 0;
}