steghide-gui/steghide-src/BmpFile.cc

849 lines
23 KiB
C++

/*
* steghide 0.5.1 - a steganography program
* Copyright (C) 1999-2003 Stefan Hetzl <shetzl@chello.at>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <cstdio>
#include <cstdlib>
#include "AUtils.h"
#include "BFSAPHeuristic.h"
#include "ColorPalette.h"
#include "CvrStgFile.h"
#include "DFSAPHeuristic.h"
#include "DMDConstructionHeuristic.h"
#include "BmpFile.h"
#include "BmpPaletteSampleValue.h"
#include "BmpRGBSampleValue.h"
#include "SampleValueAdjacencyList.h"
#include "SMDConstructionHeuristic.h"
#include "WKSConstructionHeuristic.h"
#include "common.h"
#include "error.h"
BmpFile::BmpFile (BinaryIO *io)
: CvrStgFile()
{
read (io) ;
}
BmpFile::~BmpFile ()
{
delete Palette ;
}
BmpFile::SUBFORMAT BmpFile::getSubformat () const
{
return subformat ;
}
void BmpFile::read (BinaryIO *io)
{
CvrStgFile::read (io) ;
Palette = NULL ;
readheaders() ;
readdata() ;
}
void BmpFile::write ()
{
CvrStgFile::write() ;
writeheaders() ;
writedata() ;
}
std::list<CvrStgFile::Property> BmpFile::getProperties () const
{
std::list<CvrStgFile::Property> retval ;
// format
std::string formatstring ;
switch (getSubformat()) {
case WIN:
formatstring = _("Windows 3.x bitmap") ;
break ;
case OS2:
formatstring = _("OS/2 1.x bitmap") ;
break ;
}
retval.push_back (CvrStgFile::Property (_("format"), formatstring)) ;
return retval ;
}
std::vector<MatchingAlgorithm*> BmpFile::getMatchingAlgorithms (Graph* g, Matching* m) const
{
std::vector<MatchingAlgorithm*> retval ;
if (getBitCount() == 24) {
retval.push_back (new SMDConstructionHeuristic (g, m)) ;
}
else {
retval.push_back (new SMDConstructionHeuristic (g, m)) ;
}
return retval ;
}
unsigned long BmpFile::getNumSamples() const
{
unsigned long retval = 0 ;
switch (getSubformat()) {
case WIN: {
retval = bmih.biWidth * bmih.biHeight ;
break ; }
case OS2: {
retval = bmch.bcWidth * bmch.bcHeight ;
break ; }
}
return retval ;
}
void BmpFile::replaceSample (const SamplePos pos, const SampleValue* s)
{
unsigned long index = 0 ;
unsigned short firstbit = 0 ;
calcIndex (pos, &index, &firstbit) ;
unsigned short bitcount = getBitCount() ;
switch (bitcount) {
case 1: case 4: case 8: {
const BmpPaletteSampleValue* sample = dynamic_cast<const BmpPaletteSampleValue*> (s) ;
myassert (sample) ;
for (unsigned short i = 0 ; i < bitcount ; i++) {
BitmapData[index] = BitmapData[index] & (~(1 << (firstbit + i))) ;
BitmapData[index] = BitmapData[index] | ((sample->getIndex() & (1 << i)) << firstbit) ;
}
break ; }
case 24: {
const BmpRGBSampleValue* sample = dynamic_cast<const BmpRGBSampleValue*> (s) ;
myassert (sample) ;
BitmapData[index] = sample->getBlue() ;
BitmapData[index + 1] = sample->getGreen() ;
BitmapData[index + 2] = sample->getRed() ;
break ; }
}
}
SampleValue *BmpFile::getSampleValue (SamplePos pos) const
{
unsigned long index = 0 ;
unsigned short firstbit = 0 ;
calcIndex (pos, &index, &firstbit) ;
unsigned short bitcount = getBitCount() ;
SampleValue *retval = NULL ;
switch (bitcount) {
case 1: case 4: case 8: {
BYTE idx_pal = 0 ;
for (unsigned short i = 0 ; i < bitcount ; i++) {
idx_pal |= ((BitmapData[index] & (1 << (firstbit + i))) >> firstbit) ;
}
retval = (SampleValue*) new BmpPaletteSampleValue (idx_pal) ;
break ; }
case 24: {
retval = (SampleValue*) new BmpRGBSampleValue (BitmapData[index + 2], BitmapData[index + 1], BitmapData[index]) ;
break ; }
}
return retval ;
}
std::vector<SampleValueAdjacencyList*> BmpFile::calcSVAdjacencyLists (const std::vector<SampleValue*>& svs) const
{
if (getBitCount() == 24) {
EmbValue m = getEmbValueModulus() ;
UWORD32 r = getRadius() ;
// create svalists
std::vector<SampleValueAdjacencyList*> lists (m) ;
for (EmbValue i = 0 ; i < m ; i++) {
lists[i] = new SampleValueAdjacencyList (svs.size()) ;
}
// redmap contains all sample values in a 3-dimensional RGB-tree
typedef std::map<BYTE, BmpRGBSampleValue*> BlueMap ;
typedef std::map<BYTE, BlueMap> GreenMap ;
typedef std::map<BYTE, GreenMap> RedMap ;
RedMap redmap ;
for (std::vector<SampleValue*>::const_iterator svit = svs.begin() ; svit != svs.end() ; svit++) {
BmpRGBSampleValue* rgbsv = (BmpRGBSampleValue*) (*svit) ;
redmap[rgbsv->getRed()][rgbsv->getGreen()][rgbsv->getBlue()] = rgbsv ;
}
// create hemisphere matrix (will contain a discrete hemisphere with radius getRadius())
unsigned short r_eucl = (unsigned short) sqrt (r) ; // the euclidean radius (not squared) - rounded to next lower natural number
short hemisphere[2 * r_eucl + 1][2 * r_eucl + 1] ;
for (short dr = -r_eucl ; dr <= r_eucl ; dr++) {
for (short dg = -r_eucl ; dg <= r_eucl ; dg++) {
short db_sq = r_eucl*r_eucl - dr*dr - dg*dg ;
if (db_sq >= 0) {
// round hemishpere points to next lower natural numbers
hemisphere[dr + r_eucl][dg + r_eucl] = (short) sqrt (db_sq) ;
}
else {
hemisphere[dr + r_eucl][dg + r_eucl] = -1 ;
}
}
}
//
// fill adjacency lists
//
// create reservoir - for every i reservoir[i] contains the sample values that are neighbourss of
// the sample value with label i and have a lower label (and have already been found)
// This is necessary to use collapsing trees together with bucket sort (without huge increase in memory usage)
std::vector<BmpRGBSampleValue*> reservoir[svs.size()] ;
// neighbours sorted by distance (for the current source sample value)
std::vector<BmpRGBSampleValue*> neighbours_byd[r + 1] ;
for (std::vector<SampleValue*>::const_iterator srcsvit = svs.begin() ; srcsvit != svs.end() ; srcsvit++) {
BmpRGBSampleValue* srcsv = (BmpRGBSampleValue*) (*srcsvit) ;
// sort reservoir into neighbours_byd
for (std::vector<BmpRGBSampleValue*>::const_iterator it = reservoir[srcsv->getLabel()].begin() ;
it != reservoir[srcsv->getLabel()].end() ; it++) {
neighbours_byd[srcsv->calcDistance(*it)].push_back (*it) ;
}
unsigned short r_abs_start = AUtils::bminus<unsigned short> (srcsv->getRed(), r_eucl) ;
unsigned short r_abs_end = AUtils::bplus<unsigned short, 255> (srcsv->getRed(), r_eucl) ;
unsigned short g_abs_start = AUtils::bminus<unsigned short> (srcsv->getGreen(), r_eucl) ;
unsigned short g_abs_end = AUtils::bplus<unsigned short, 255> (srcsv->getGreen(), r_eucl) ;
RedMap::iterator rit = redmap.lower_bound (r_abs_start) ;
while ((rit != redmap.end()) && (rit->first <= r_abs_end)) {
GreenMap& greenmap = rit->second ;
if (greenmap.empty()) {
RedMap::iterator delme = rit ;
rit++ ;
redmap.erase (delme) ;
}
else {
GreenMap::iterator git = greenmap.lower_bound (g_abs_start) ;
while ((git != greenmap.end()) && (git->first <= g_abs_end)) {
unsigned short red_index = (rit->first - srcsv->getRed()) + r_eucl ;
unsigned short green_index = (git->first - srcsv->getGreen()) + r_eucl ;
short delta_b = hemisphere[red_index][green_index] ;
if (delta_b < 0) { // this blue map has no sample values in sphere
git++ ;
}
else {
BlueMap& bluemap = git->second ;
if (bluemap.empty()) {
GreenMap::iterator delme = git ;
git++ ;
greenmap.erase (delme) ;
}
else {
unsigned short b_abs_start = AUtils::bminus<unsigned short> (srcsv->getBlue(), delta_b) ;
unsigned short b_abs_end = AUtils::bplus<unsigned short,255> (srcsv->getBlue(), delta_b) ;
BlueMap::iterator bit = bluemap.lower_bound (b_abs_start) ;
while ((bit != bluemap.end()) && (bit->first <= b_abs_end)) {
if (srcsv->getLabel() < bit->second->getLabel()) {
neighbours_byd[srcsv->calcDistance(bit->second)].push_back (bit->second) ;
reservoir[bit->second->getLabel()].push_back (srcsv) ;
bit++ ;
}
else {
BlueMap::iterator delme = bit ;
bit++ ;
bluemap.erase (delme) ;
}
}
git++ ;
}
}
} // end of git loop
rit++ ;
}
} // end of rit loop
for (unsigned short d = 0 ; d <= r ; d++) {
if (!neighbours_byd[d].empty()) {
for (std::vector<BmpRGBSampleValue*>::const_iterator it = neighbours_byd[d].begin() ;
it != neighbours_byd[d].end() ; it++) {
(*(lists[(*it)->getEmbeddedValue()]))[srcsv].push_back (*it) ;
}
neighbours_byd[d].clear() ;
}
}
} // end of svs for loop
return lists ;
}
else {
return CvrStgFile::calcSVAdjacencyLists(svs) ;
}
}
void BmpFile::calcIndex (SamplePos pos, unsigned long* index, unsigned short* firstbit) const
{
unsigned long width = getWidth(), bitcount = getBitCount() ;
unsigned long bytesperline_nonpadded = 0 ;
if (width * bitcount % 8 == 0) {
bytesperline_nonpadded = (width * bitcount) / 8 ;
}
else {
bytesperline_nonpadded = (width * bitcount) / 8 + 1 ;
}
unsigned long row = pos / width ;
pos = pos % width ;
unsigned long column = 0 ;
switch (bitcount) {
case 1: case 4: case 8:
{
unsigned short samplesperbyte = 8 / bitcount ;
column = pos / samplesperbyte ;
// to account for the order pixels are stored in one byte:
*firstbit = (samplesperbyte - (pos % samplesperbyte) - 1) * bitcount ;
myassert (*firstbit < 8) ;
}
break ;
case 24:
column = pos * 3 ;
*firstbit = 0 ;
break ;
default:
myassert(false) ;
break ;
}
*index = bytesperline_nonpadded * row + column ;
}
unsigned short BmpFile::getBitCount() const
{
unsigned short retval = 0 ;
switch (getSubformat()) {
case WIN: {
retval = bmih.biBitCount ;
break ; }
case OS2: {
retval = bmch.bcBitCount ;
break ; }
}
myassert (retval == 1 || retval == 4 || retval == 8 || retval == 24) ;
return retval ;
}
unsigned long BmpFile::getWidth() const
{
unsigned long retval = 0 ;
switch (getSubformat()) {
case WIN:
retval = bmih.biWidth ;
break ;
case OS2:
retval = bmch.bcWidth ;
break ;
}
return retval ;
}
unsigned long BmpFile::getHeight() const
{
unsigned long retval = 0 ;
switch (getSubformat()) {
case WIN: {
retval = bmih.biHeight ;
break ; }
case OS2: {
retval = bmch.bcHeight ;
break ; }
}
return retval ;
}
ColorPalette *BmpFile::getPalette() const
{
myassert (getBitCount() != 24) ;
myassert (Palette) ;
return Palette ;
}
/* reads the headers of a bmp file from disk */
void BmpFile::readheaders ()
{
try {
bmfh.bfType = IdBm ;
bmfh.bfSize = getBinIO()->read32_le() ;
bmfh.bfReserved1 = getBinIO()->read16_le() ;
bmfh.bfReserved2 = getBinIO()->read16_le() ;
bmfh.bfOffBits = getBinIO()->read32_le() ;
unsigned long tmpSize = getBinIO()->read32_le() ;
switch (tmpSize) {
case SizeBMINFOHEADER: {
// this file is in the Windows bmp format
subformat = WIN ;
bmpwin_readheaders () ;
break ; }
case SizeBMCOREHEADER: {
// this file is in the OS/2 bmp format
subformat = OS2 ;
bmpos2_readheaders () ;
break ; }
default: {
if (getBinIO()->is_std()) {
throw NotImplementedError (_("the bmp data from standard input has a format that is not supported (biSize: %lu)."), tmpSize) ;
}
else {
throw NotImplementedError (_("the bmp file \"%s\" has a format that is not supported (biSize: %lu)."), getBinIO()->getName().c_str(), tmpSize) ;
}
break ; }
}
}
catch (BinaryInputError e) {
switch (e.getType()) {
case BinaryInputError::FILE_ERR: {
throw SteghideError (_("an error occured while reading the bmp headers from the file \"%s\"."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryInputError::FILE_EOF: {
throw SteghideError (_("premature end of file \"%s\" while reading bmp headers."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryInputError::STDIN_ERR: {
throw SteghideError (_("an error occured while reading the bmp headers from standard input.")) ;
break ; }
case BinaryInputError::STDIN_EOF: {
throw SteghideError (_("premature end of data from standard input while reading bmp headers.")) ;
break ; }
}
}
}
void BmpFile::bmpwin_readheaders ()
{
bmih.biSize = SizeBMINFOHEADER ;
bmih.biWidth = getBinIO()->read32_le () ;
bmih.biHeight = getBinIO()->read32_le () ;
bmih.biPlanes = getBinIO()->read16_le () ;
myassert (bmih.biPlanes == 1) ;
bmih.biBitCount = getBinIO()->read16_le () ;
switch (bmih.biBitCount) {
case 1:
setSamplesPerVertex (SamplesPerVertex_SmallPalette) ;
setEmbValueModulus (EmbValueModulus_SmallPalette) ;
setRadius (Radius_Palette) ;
break ;
case 4:
setSamplesPerVertex (SamplesPerVertex_SmallPalette) ;
setEmbValueModulus (EmbValueModulus_SmallPalette) ;
setRadius (Radius_Palette) ;
break ;
case 8:
setSamplesPerVertex (SamplesPerVertex_LargePalette) ;
setEmbValueModulus (EmbValueModulus_LargePalette) ;
setRadius (Radius_Palette) ;
break ;
case 24:
setSamplesPerVertex (SamplesPerVertex_RGB) ;
setEmbValueModulus (EmbValueModulus_RGB) ;
setRadius (Radius_RGB) ;
break ;
default:
if (getBinIO()->is_std()) {
throw NotImplementedError (_("the bmp data from standard input has a format that is not supported (biBitCount: %d)."), bmih.biBitCount) ;
}
else {
throw NotImplementedError (_("the bmp file \"%s\" has a format that is not supported (biBitCount: %d)."), getBinIO()->getName().c_str(), bmih.biBitCount) ;
}
break ;
}
bmih.biCompression = getBinIO()->read32_le () ;
if (bmih.biCompression != COMPRESSION_BI_RGB) {
if (getBinIO()->is_std()) {
throw NotImplementedError (_("the bitmap data from standard input is compressed which is not supported.")) ;
}
else {
throw NotImplementedError (_("the bitmap data in \"%s\" is compressed which is not supported."), getBinIO()->getName().c_str()) ;
}
}
bmih.biSizeImage = getBinIO()->read32_le () ;
bmih.biXPelsPerMeter = getBinIO()->read32_le () ;
bmih.biYPelsPerMeter = getBinIO()->read32_le () ;
bmih.biClrUsed = getBinIO()->read32_le () ;
bmih.biClrImportant = getBinIO()->read32_le () ;
if (bmih.biBitCount != 24) {
/* a color table exists */
Palette = new ColorPalette() ;
unsigned int ncolors = 0 ;
switch (bmih.biBitCount) {
case 1: {
if (Args.Command.getValue() == EMBED) {
Warning w (_("using a black/white bitmap as cover is very insecure!")) ;
w.printMessage() ;
}
ncolors = 2 ;
break ; }
case 4: {
if (Args.Command.getValue() == EMBED) {
Warning w (_("using a 16-color bitmap as cover is very insecure!")) ;
w.printMessage() ;
}
ncolors = 16 ;
break ; }
case 8: {
ncolors = 256 ;
break ; }
default: {
myassert (0) ;
break ; }
}
if (bmih.biClrUsed != 0) {
ncolors = bmih.biClrUsed ;
}
for (unsigned int i = 0 ; i < ncolors ; i++) {
unsigned char b = getBinIO()->read8() ;
unsigned char g = getBinIO()->read8() ;
unsigned char r = getBinIO()->read8() ;
if (getBinIO()->read8() != 0) {
Warning w (_("maybe corrupted windows bmp data (Reserved in RGBQUAD is non-zero).")) ;
w.printMessage() ;
}
Palette->addEntry(r, g, b) ;
}
}
}
void BmpFile::bmpos2_readheaders ()
{
bmch.bcSize = SizeBMCOREHEADER ;
bmch.bcWidth = getBinIO()->read16_le () ;
bmch.bcHeight = getBinIO()->read16_le () ;
bmch.bcPlanes = getBinIO()->read16_le () ;
myassert (bmch.bcPlanes == 1) ;
bmch.bcBitCount = getBinIO()->read16_le () ;
switch (bmch.bcBitCount) {
case 1:
setSamplesPerVertex (SamplesPerVertex_SmallPalette) ;
setEmbValueModulus (EmbValueModulus_SmallPalette) ;
setRadius (Radius_Palette) ;
break ;
case 4:
setSamplesPerVertex (SamplesPerVertex_SmallPalette) ;
setEmbValueModulus (EmbValueModulus_SmallPalette) ;
setRadius (Radius_Palette) ;
break ;
case 8:
setSamplesPerVertex (SamplesPerVertex_LargePalette) ;
setEmbValueModulus (EmbValueModulus_LargePalette) ;
setRadius (Radius_Palette) ;
break ;
case 24:
setSamplesPerVertex (SamplesPerVertex_RGB) ;
setEmbValueModulus (EmbValueModulus_RGB) ;
setRadius (Radius_RGB) ;
break ;
default:
if (getBinIO()->is_std()) {
throw NotImplementedError (_("the bmp data from standard input has a format that is not supported (bcBitCount: %d)."), bmch.bcBitCount) ;
}
else {
throw NotImplementedError (_("the bmp file \"%s\" has a format that is not supported (bcBitCount: %d)."), getBinIO()->getName().c_str(), bmch.bcBitCount) ;
}
break ;
}
if (bmch.bcBitCount != 24) {
/* a color table exists */
unsigned int ncolors = 0 ;
Palette = new ColorPalette() ;
switch (bmch.bcBitCount) {
case 1: {
if (Args.Command.getValue() == EMBED) {
Warning w (_("using a black/white bitmap as cover is very insecure!")) ;
w.printMessage() ;
}
ncolors = 2 ;
break ; }
case 4: {
if (Args.Command.getValue() == EMBED) {
Warning w (_("using a 16-color bitmap as cover is very insecure!")) ;
w.printMessage() ;
}
ncolors = 16 ;
break ; }
case 8: {
ncolors = 256 ;
break ; }
default: {
myassert (0) ;
break ; }
}
for (unsigned int i = 0 ; i < ncolors ; i++) {
unsigned char b = getBinIO()->read8() ;
unsigned char g = getBinIO()->read8() ;
unsigned char r = getBinIO()->read8() ;
Palette->addEntry (r, g, b) ;
}
}
}
/* writes the headers of a bmp file to disk */
void BmpFile::writeheaders ()
{
try {
getBinIO()->write16_le (bmfh.bfType) ;
getBinIO()->write32_le (bmfh.bfSize) ;
getBinIO()->write16_le (bmfh.bfReserved1) ;
getBinIO()->write16_le (bmfh.bfReserved2) ;
getBinIO()->write32_le (bmfh.bfOffBits) ;
switch (getSubformat()) {
case WIN: {
bmpwin_writeheaders() ;
break ; }
case OS2: {
bmpos2_writeheaders() ;
break ; }
default: {
myassert (0) ;
break ; }
}
}
catch (BinaryOutputError e) {
switch (e.getType()) {
case BinaryOutputError::FILE_ERR: {
throw SteghideError (_("an error occured while writing the bmp headers to the file \"%s\"."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryOutputError::STDOUT_ERR: {
throw SteghideError (_("an error occured while writing the bmp headers to standard output.")) ;
break ; }
}
}
}
void BmpFile::bmpwin_writeheaders ()
{
getBinIO()->write32_le (bmih.biSize) ;
getBinIO()->write32_le (bmih.biWidth) ;
getBinIO()->write32_le (bmih.biHeight) ;
getBinIO()->write16_le (bmih.biPlanes) ;
getBinIO()->write16_le (bmih.biBitCount) ;
getBinIO()->write32_le (bmih.biCompression) ;
getBinIO()->write32_le (bmih.biSizeImage) ;
getBinIO()->write32_le (bmih.biXPelsPerMeter) ;
getBinIO()->write32_le (bmih.biYPelsPerMeter) ;
getBinIO()->write32_le (bmih.biClrUsed) ;
getBinIO()->write32_le (bmih.biClrImportant) ;
if (Palette != NULL) {
for (unsigned int i = 0 ; i < Palette->getSize() ; i++) {
getBinIO()->write8 ((*Palette)[i].Blue) ;
getBinIO()->write8 ((*Palette)[i].Green) ;
getBinIO()->write8 ((*Palette)[i].Red) ;
getBinIO()->write8 (0) ;
}
}
}
void BmpFile::bmpos2_writeheaders ()
{
getBinIO()->write32_le (bmch.bcSize) ;
getBinIO()->write16_le (bmch.bcWidth) ;
getBinIO()->write16_le (bmch.bcHeight) ;
getBinIO()->write16_le (bmch.bcPlanes) ;
getBinIO()->write16_le (bmch.bcBitCount) ;
if (Palette != NULL) {
for (unsigned int i = 0 ; i < Palette->getSize() ; i++) {
getBinIO()->write8 ((*Palette)[i].Blue) ;
getBinIO()->write8 ((*Palette)[i].Green) ;
getBinIO()->write8 ((*Palette)[i].Red) ;
}
}
}
/* returns the number of bytes used to store the pixel data of one scan line */
unsigned long BmpFile::calcLinelength ()
{
unsigned long retval = 0 ;
switch (getSubformat()) {
case WIN: {
if (bmih.biBitCount * bmih.biWidth % 8 == 0) {
retval = bmih.biBitCount * bmih.biWidth / 8 ;
}
else {
retval = (bmih.biBitCount * bmih.biWidth / 8) + 1;
}
break ; }
case OS2: {
if (bmch.bcBitCount * bmch.bcWidth % 8 == 0) {
retval = bmch.bcBitCount * bmch.bcWidth / 8 ;
}
else {
retval = (bmch.bcBitCount * bmch.bcWidth / 8) + 1;
}
break ; }
default: {
myassert (0) ;
break ; }
}
return retval ;
}
/* reads a bmp file from disk into a CVRSTGFILE structure */
void BmpFile::readdata ()
{
try {
unsigned long linelength = calcLinelength () ;
unsigned long height = getHeight () ;
int paddinglength = 0 ;
if (linelength % 4 == 0) {
paddinglength = 0 ;
}
else {
paddinglength = 4 - (linelength % 4) ;
}
BitmapData.resize (height * linelength) ;
for (unsigned long line = 0 ; line < height ; line++) {
for (unsigned long posinline = 0 ; posinline < linelength ; posinline++) {
BitmapData[line * linelength + posinline] = getBinIO()->read8() ;
}
for (int i = 0 ; i < paddinglength ; i++) {
if (getBinIO()->read8() != 0) {
Warning w (_("maybe corrupted bmp data (padding byte at 0x%lx set to non-zero)."), getBinIO()->getPos() - 1) ;
w.printMessage() ;
}
}
}
atend.clear() ;
while (!getBinIO()->eof()) {
atend.push_back (getBinIO()->read8()) ;
}
}
catch (BinaryInputError e) {
switch (e.getType()) {
case BinaryInputError::FILE_ERR: {
throw SteghideError (_("an error occured while reading the bmp data from the file \"%s\"."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryInputError::FILE_EOF: {
throw SteghideError (_("premature end of file \"%s\" while reading bmp data."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryInputError::STDIN_ERR: {
throw SteghideError (_("an error occured while reading the bmp data from standard input.")) ;
break ; }
case BinaryInputError::STDIN_EOF: {
throw SteghideError (_("premature end of bmp data from standard input.")) ;
break ; }
}
}
}
void BmpFile::writedata ()
{
try {
unsigned long linelength = calcLinelength () ;
unsigned long height = getHeight () ;
unsigned int paddinglength = 0 ;
if (linelength % 4 == 0) {
paddinglength = 0 ;
}
else {
paddinglength = 4 - (linelength % 4) ;
}
for (unsigned long line = 0 ; line < height ; line++) {
for (unsigned long posinline = 0 ; posinline < linelength ; posinline++) {
getBinIO()->write8 (BitmapData[line * linelength + posinline]) ;
}
// write padding bytes
for (unsigned int i = 0 ; i < paddinglength ; i++) {
getBinIO()->write8 (0) ;
}
}
for (std::vector<unsigned char>::iterator i = atend.begin() ; i != atend.end() ; i++) {
getBinIO()->write8 (*i) ;
}
}
catch (BinaryOutputError e) {
switch (e.getType()) {
case BinaryOutputError::FILE_ERR: {
throw SteghideError (_("an error occured while writing the bitmap data to the file \"%s\"."), getBinIO()->getName().c_str()) ;
break ; }
case BinaryOutputError::STDOUT_ERR: {
throw SteghideError (_("an error occured while writing the bitmap data to standard output.")) ;
break ; }
}
}
}