2019-01-05 17:20:33 +00:00
# include "paletteparser.h"
# include "log.h"
# include <QFileInfo>
# include <QRegularExpression>
PaletteParser : : PaletteParser ( )
{
}
QList < QRgb > PaletteParser : : parse ( QString filepath , bool * error ) {
QFileInfo info ( filepath ) ;
QString extension = info . completeSuffix ( ) ;
if ( extension . isNull ( ) ) {
logError ( QString ( " Failed to parse palette file '%1' because it has an unrecognized extension '%2' " ) . arg ( filepath ) . arg ( extension ) ) ;
* error = true ;
return QList < QRgb > ( ) ;
}
extension = extension . toLower ( ) ;
if ( extension = = " pal " ) {
return parsePal ( filepath , error ) ;
} else if ( extension = = " act " ) {
return parseAdobeColorTable ( filepath , error ) ;
} else if ( extension = = " tpl " ) {
return parseTileLayerPro ( filepath , error ) ;
} else if ( extension = = " gpl " ) {
return parseAdvancePaletteEditor ( filepath , error ) ;
} else {
logError ( QString ( " Unsupported palette file. Supported formats are: .pal " ) ) ;
* error = true ;
}
return QList < QRgb > ( ) ;
}
QList < QRgb > PaletteParser : : parsePal ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
logError ( QString ( " Could not open palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
return QList < QRgb > ( ) ;
}
QTextStream in ( & file ) ;
QString firstLine = in . readLine ( ) ;
if ( firstLine = = " JASC-PAL " ) {
file . close ( ) ;
return parseJASC ( filepath , error ) ;
} else {
file . close ( ) ;
return parseAdvanceMapPal ( filepath , error ) ;
}
}
QList < QRgb > PaletteParser : : parseJASC ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
logError ( QString ( " Could not open JASC palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
return QList < QRgb > ( ) ;
}
QTextStream in ( & file ) ;
if ( in . readLine ( ) ! = " JASC-PAL " ) {
* error = true ;
logError ( QString ( " JASC palette file '%1' had an unexpected format. First line must be 'JASC-PAL'. " ) . arg ( filepath ) ) ;
file . close ( ) ;
return QList < QRgb > ( ) ;
}
if ( in . readLine ( ) ! = " 0100 " ) {
* error = true ;
logError ( QString ( " JASC palette file '%1' had an unexpected format. Second line must be '0100'. " ) . arg ( filepath ) ) ;
file . close ( ) ;
return QList < QRgb > ( ) ;
}
QString numColorsStr = in . readLine ( ) ;
bool numOk ;
int numColors = numColorsStr . toInt ( & numOk ) ;
if ( ! numOk ) {
* error = true ;
logError ( QString ( " JASC palette file '%1' had an unexpected format. Third line must be the number of colors. " ) . arg ( filepath ) ) ;
return QList < QRgb > ( ) ;
}
QList < QRgb > palette ;
QRegularExpression re ( " (?<red> \\ d+) \ \ s ( ? < green > \ \ d + ) \ \ s ( ? < blue > \ \ d + ) " ) ;
while ( ! in . atEnd ( ) & & numColors > 0 ) {
numColors - - ;
QString line = in . readLine ( ) ;
QRegularExpressionMatch match = re . match ( line ) ;
if ( match . hasMatch ( ) ) {
QString redStr = match . captured ( " red " ) ;
QString greenStr = match . captured ( " green " ) ;
QString blueStr = match . captured ( " blue " ) ;
bool redOk , greenOk , blueOk ;
int red = redStr . toInt ( & redOk ) ;
int green = greenStr . toInt ( & greenOk ) ;
int blue = blueStr . toInt ( & blueOk ) ;
if ( ! redOk | | ! greenOk | | ! blueOk ) {
* error = true ;
logError ( QString ( " JASC palette file '%1' had an unexpected format. Invalid color '%2'. " ) . arg ( filepath ) . arg ( line ) ) ;
return QList < QRgb > ( ) ;
}
palette . append ( qRgb ( this - > clampColorValue ( red ) ,
this - > clampColorValue ( green ) ,
this - > clampColorValue ( blue ) ) ) ;
} else {
* error = true ;
logError ( QString ( " JASC palette file '%1' had an unexpected format. Invalid color '%2'. " ) . arg ( filepath ) . arg ( line ) ) ;
file . close ( ) ;
return QList < QRgb > ( ) ;
}
}
file . close ( ) ;
return palette ;
}
QList < QRgb > PaletteParser : : parseAdvanceMapPal ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
2019-01-09 00:04:41 +00:00
logError ( QString ( " Could not open Advance Map 1.92 palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
2019-01-05 17:20:33 +00:00
return QList < QRgb > ( ) ;
}
QByteArray in = file . readAll ( ) ;
file . close ( ) ;
if ( in . length ( ) % 4 ! = 0 ) {
* error = true ;
2019-01-09 00:04:41 +00:00
logError ( QString ( " Advance Map 1.92 palette file '%1' had an unexpected format. File's length must be a multiple of 4, but the length is %2. " ) . arg ( filepath ) . arg ( in . length ( ) ) ) ;
2019-01-05 17:20:33 +00:00
return QList < QRgb > ( ) ;
}
QList < QRgb > palette ;
int i = 0 ;
while ( i < in . length ( ) ) {
2019-01-09 00:04:41 +00:00
unsigned char red = static_cast < unsigned char > ( in . at ( i ) ) ;
2019-01-05 17:20:33 +00:00
unsigned char green = static_cast < unsigned char > ( in . at ( i + 1 ) ) ;
2019-01-09 00:04:41 +00:00
unsigned char blue = static_cast < unsigned char > ( in . at ( i + 2 ) ) ;
2019-01-05 17:20:33 +00:00
palette . append ( qRgb ( this - > clampColorValue ( red ) ,
this - > clampColorValue ( green ) ,
this - > clampColorValue ( blue ) ) ) ;
i + = 4 ;
}
return palette ;
}
QList < QRgb > PaletteParser : : parseAdobeColorTable ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
logError ( QString ( " Could not open Adobe Color Table palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
return QList < QRgb > ( ) ;
}
QByteArray in = file . readAll ( ) ;
file . close ( ) ;
if ( in . length ( ) ! = 0x300 ) {
* error = true ;
logError ( QString ( " Adobe Color Table palette file '%1' had an unexpected format. File's length must be exactly 768, but the length is %2. " ) . arg ( filepath ) . arg ( in . length ( ) ) ) ;
return QList < QRgb > ( ) ;
}
QList < QRgb > palette ;
int i = 0 ;
while ( i < in . length ( ) ) {
unsigned char red = static_cast < unsigned char > ( in . at ( i ) ) ;
unsigned char green = static_cast < unsigned char > ( in . at ( i + 1 ) ) ;
unsigned char blue = static_cast < unsigned char > ( in . at ( i + 2 ) ) ;
palette . append ( qRgb ( this - > clampColorValue ( red ) ,
this - > clampColorValue ( green ) ,
this - > clampColorValue ( blue ) ) ) ;
i + = 3 ;
}
return palette ;
}
QList < QRgb > PaletteParser : : parseTileLayerPro ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
logError ( QString ( " Could not open Tile Layer Pro palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
return QList < QRgb > ( ) ;
}
QByteArray in = file . readAll ( ) ;
file . close ( ) ;
if ( in . length ( ) < 4 | | in . at ( 0 ) ! = ' T ' | | in . at ( 1 ) ! = ' L ' | | in . at ( 2 ) ! = ' P ' | | in . at ( 3 ) ! = 0 ) {
* error = true ;
logError ( QString ( " Tile Layer Pro palette file '%1' had an unexpected format. The TLP header is missing. " ) . arg ( filepath ) . arg ( in . length ( ) ) ) ;
return QList < QRgb > ( ) ;
}
if ( in . length ( ) ! = 0x304 ) {
* error = true ;
logError ( QString ( " Tile Layer Pro palette file '%1' had an unexpected format. File's length must be exactly 772, but the length is %2. " ) . arg ( filepath ) . arg ( in . length ( ) ) ) ;
return QList < QRgb > ( ) ;
}
QList < QRgb > palette ;
int i = 4 ;
while ( i < in . length ( ) ) {
unsigned char red = static_cast < unsigned char > ( in . at ( i ) ) ;
unsigned char green = static_cast < unsigned char > ( in . at ( i + 1 ) ) ;
unsigned char blue = static_cast < unsigned char > ( in . at ( i + 2 ) ) ;
palette . append ( qRgb ( this - > clampColorValue ( red ) ,
this - > clampColorValue ( green ) ,
this - > clampColorValue ( blue ) ) ) ;
i + = 3 ;
}
return palette ;
}
QList < QRgb > PaletteParser : : parseAdvancePaletteEditor ( QString filepath , bool * error ) {
QFile file ( filepath ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
* error = true ;
logError ( QString ( " Could not open GPL palette file '%1': " ) . arg ( filepath ) + file . errorString ( ) ) ;
return QList < QRgb > ( ) ;
}
QTextStream in ( & file ) ;
if ( in . readLine ( ) ! = " [APE Palette] " ) {
* error = true ;
logError ( QString ( " GPL palette file '%1' had an unexpected format. First line must be '[APE Palette]'. " ) . arg ( filepath ) ) ;
file . close ( ) ;
return QList < QRgb > ( ) ;
}
QList < QRgb > palette ;
while ( ! in . atEnd ( ) ) {
QString line = in . readLine ( ) . trimmed ( ) ;
if ( line . isEmpty ( ) ) {
continue ;
}
bool ok ;
unsigned int raw = line . toUInt ( & ok ) ;
if ( ! ok ) {
* error = true ;
logError ( QString ( " GPL palette file '%1' had an unexpected format. Invalid color '%2'. " ) . arg ( filepath ) . arg ( line ) ) ;
file . close ( ) ;
return QList < QRgb > ( ) ;
}
raw = ( ( raw & 0xFF ) < < 8 ) | ( ( raw > > 8 ) & 0xFF ) ;
int red = ( raw & 0x1F ) * 8 ;
int green = ( ( raw > > 5 ) & 0x1F ) * 8 ;
int blue = ( ( raw > > 10 ) & 0x1F ) * 8 ;
palette . append ( qRgb ( this - > clampColorValue ( red ) ,
this - > clampColorValue ( green ) ,
this - > clampColorValue ( blue ) ) ) ;
}
file . close ( ) ;
return palette ;
}
int PaletteParser : : clampColorValue ( int value ) {
if ( value < 0 ) {
value = 0 ;
}
if ( value > 255 ) {
value = 255 ;
}
return value ;
}