Is there a way in LibTiff how I can read a file from Memory and save it to Memory?
I don't want to save the image to the disc first, before opening it with an other library...
Thanks so much!
I know this is an old question, but I am going to post an easier, more up-to-date answer for those like myself who need this information for more recent versions of libtiff. In the newest version of libtiff (4.0.2), and even the past few versions I believe (check for your specific version number), there is an include file called tiffio.hxx. It has two extern functions for reading/writing to streams in memory:
extern TIFF* TIFFStreamOpen(const char*, std::ostream *);
extern TIFF* TIFFStreamOpen(const char*, std::istream *);
You can just include this file and read or write to memory.
Writing example:
#include <tiffio.h>
#include <tiffio.hxx>
#include <sstream>
std::ostringstream output_TIFF_stream;
//Note: because this is an in memory TIFF, just use whatever you want for the name - we
//aren't using it to read from a file
TIFF* mem_TIFF = TIFFStreamOpen("MemTIFF", &output_TIFF_stream);
//perform normal operations on mem_TIFF here like setting fields
//...
//Write image data to the TIFF
//..
TIFFClose(mem_TIFF);
//Now output_TIFF_stream has all of my image data. I can do whatever I need to with it.
Reading is very similar:
#include <tiffio.h>
#include <tiffio.hxx>
#include <sstream>
std::istringstream input_TIFF_stream;
//Populate input_TIFF_stream with TIFF image data
//...
TIFF* mem_TIFF = TIFFStreamOpen("MemTIFF", &input_TIFF_stream);
//perform normal operations on mem_TIFF here reading fields
//...
TIFFClose(mem_TIFF);
These are very simple examples, but you can see that by using TIFFStreamOpen you don't have to override those functions and pass them to TIFFClientOpen.
You should create your own read/write/etc. functions and pass them to TIFFClientOpen (not TIFFOpen) function when creating your TIFF.
Example:
TIFF* tif = TIFFClientOpen(
"Memory", "w", (thandle_t)something_you_will_use_later,
tiff_Read, tiff_Write, tiff_Seek, tiff_Close, tiff_Size,
tiff_Map, tiff_Unmap);
And you should also implement following functions (st passed to these functions is the something_you_will_use_later passed to TIFFClientOpen :
tsize_t tiff_Read(thandle_t st,tdata_t buffer,tsize_t size)
{
...
};
tsize_t tiff_Write(thandle_t st,tdata_t buffer,tsize_t size)
{
...
};
int tiff_Close(thandle_t)
{
return 0;
};
toff_t tiff_Seek(thandle_t st,toff_t pos, int whence)
{
if (pos == 0xFFFFFFFF)
return 0xFFFFFFFF;
...
};
toff_t tiff_Size(thandle_t st)
{
...
};
int tiff_Map(thandle_t, tdata_t*, toff_t*)
{
return 0;
};
void tiff_Unmap(thandle_t, tdata_t, toff_t)
{
return;
};
What I'm using...:
#define MALLOC(ptr,type,number,action) {\
if (((ptr) = (type*) malloc ((number)*sizeof(type))) == NULL) {\
(void) fprintf (stderr, "[%s: #%04d] ERROR : malloc of %lu bytes failed !\n", __FILE__, __LINE__, number*sizeof(type));\
perror ("Operating system message");\
action;}}
#define REALLOC(ptr,type,number,action) {\
if (((ptr) = (type*) realloc ((ptr), (number)*sizeof(type))) == NULL) {\
(void) fprintf (stderr, "[%s: #%04d] ERROR : realloc of %lu bytes failed!\n", __FILE__, __LINE__, number*sizeof(type));\
perror ("Operating system message");\
action;}}
#define FREE(ptr) { if (ptr != NULL) free (ptr); ptr = NULL; }
extern "C" {
typedef struct _memtiff {
unsigned char *data;
tsize_t size;
tsize_t incsiz;
tsize_t flen;
toff_t fptr;
} MEMTIFF;
static MEMTIFF *memTiffOpen(tsize_t incsiz = 10240, tsize_t initsiz = 10240)
{
MEMTIFF *memtif;
MALLOC(memtif, MEMTIFF, 1, exit(-1));
memtif->incsiz = incsiz;
if (initsiz == 0) initsiz = incsiz;
MALLOC(memtif->data, unsigned char, initsiz, exit(-1));
memtif->size = initsiz;
memtif->flen = 0;
memtif->fptr = 0;
return memtif;
}
/*===========================================================================*/
static tsize_t memTiffReadProc(thandle_t handle, tdata_t buf, tsize_t size)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
tsize_t n;
if (((tsize_t) memtif->fptr + size) <= memtif->flen) {
n = size;
}
else {
n = memtif->flen - memtif->fptr;
}
memcpy(buf, memtif->data + memtif->fptr, n);
memtif->fptr += n;
return n;
}
/*===========================================================================*/
static tsize_t memTiffWriteProc(thandle_t handle, tdata_t buf, tsize_t size)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
if (((tsize_t) memtif->fptr + size) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->fptr + memtif->incsiz + size);
memtif->size = memtif->fptr + memtif->incsiz + size;
}
memcpy (memtif->data + memtif->fptr, buf, size);
memtif->fptr += size;
if (memtif->fptr > memtif->flen) memtif->flen = memtif->fptr;
return size;
}
/*===========================================================================*/
static toff_t memTiffSeekProc(thandle_t handle, toff_t off, int whence)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
switch (whence) {
case SEEK_SET: {
if ((tsize_t) off > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->size + memtif->incsiz + off);
memtif->size = memtif->size + memtif->incsiz + off;
}
memtif->fptr = off;
break;
}
case SEEK_CUR: {
if ((tsize_t)(memtif->fptr + off) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->fptr + memtif->incsiz + off);
memtif->size = memtif->fptr + memtif->incsiz + off;
}
memtif->fptr += off;
break;
}
case SEEK_END: {
if ((tsize_t) (memtif->size + off) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->size + memtif->incsiz + off);
memtif->size = memtif->size + memtif->incsiz + off;
}
memtif->fptr = memtif->size + off;
break;
}
}
if (memtif->fptr > memtif->flen) memtif->flen = memtif->fptr;
return memtif->fptr;
}
/*===========================================================================*/
static int memTiffCloseProc(thandle_t handle)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
memtif->fptr = 0;
return 0;
}
/*===========================================================================*/
static toff_t memTiffSizeProc(thandle_t handle)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
return memtif->flen;
}
/*===========================================================================*/
static int memTiffMapProc(thandle_t handle, tdata_t* base, toff_t* psize)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
*base = memtif->data;
*psize = memtif->flen;
return (1);
}
/*===========================================================================*/
static void memTiffUnmapProc(thandle_t handle, tdata_t base, toff_t size)
{
return;
}
/*===========================================================================*/
static void memTiffFree(MEMTIFF *memtif)
{
FREE(memtif->data);
FREE(memtif);
return;
}
/*===========================================================================*/
}
And then:
if ((filepath == "-") || (filepath == "HTTP")) {
memtif = memTiffOpen();
tif = TIFFClientOpen("MEMTIFF", "wb", (thandle_t) memtif,
memTiffReadProc,
memTiffWriteProc,
memTiffSeekProc,
memTiffCloseProc,
memTiffSizeProc,
memTiffMapProc,
memTiffUnmapProc
);
}
else {
if ((tif = TIFFOpen (filepath.c_str(), "wb")) == NULL) {
if (memtif != NULL) memTiffFree(memtif);
string msg = "TIFFopen of \"" + filepath + "\" failed!";
throw SipiError(__file__, __LINE__, msg);
}
}
In order to use the in-memry buffer:
if (filepath == "-") {
size_t n = 0;
while (n < memtif->flen) {
n += fwrite (&(memtif->data[n]), 1, memtif->flen - n > 10240 ? 10240 : memtif->flen - n, stdout);
}
fflush(stdout);
memTiffFree(memtif);
}
Related
Thank you so much for answering this question.
I use lame and I want to decode mp3 file to wav.
I succeeded in decoding mp3 files into wav files through several searches.
However, the size of the wav file is created too large and an error message appears.
Media player error message :
This file cannot be played. The file format may not be supported, the file extension may be incorrect, or the file may be corrupted.
If you know my problem, please give me some advice.
Thank you
HEADER FILE
#pragma once
#ifndef _LAME_HELPER_H_
#define _LAME_HELPER_H_
#include <windows.h>
#include "lame.h"
#define LH_STARTED WM_USER+1
#define LH_COMPUTED WM_USER+2
#define LH_DONE WM_USER+3
#define LH_ERROR WM_USER+4
#define MAX_THREAD_COUNT 5
enum encode_mode_e
{
EM_ABR,
EM_CBR,
EM_VBR
};
enum encode_channel_e
{
EC_MONO,
EC_STEREO
};
enum bitrate_e
{
BR_8kbps = 8,
BR_16kbps = 16,
BR_24kbps = 24,
BR_32kbps = 32,
BR_40kbps = 40,
BR_48kbps = 48,
BR_56kbps = 56,
BR_64kbps = 64,
BR_80kbps = 80,
BR_96kbps = 96,
BR_112kbps = 112,
BR_128kbps = 128,
BR_144kbps = 144,
BR_160kbps = 160,
BR_192kbps = 192,
BR_224kbps = 224,
BR_256kbps = 256,
BR_320kbps = 320
};
enum samplerate_e
{
SR_8khz = 8000,
SR_11khz = 11025,
SR_12khz = 12000,
SR_16khz = 16000,
SR_22khz = 22050,
SR_24khz = 24000,
SR_32khz = 32000,
SR_44khz = 44100,
SR_48khz = 48000
};
struct settings_t
{
char* title;
char* artist;
char* album;
char* comment;
char* year;
char* track;
char* genre;
char* albumart;
encode_channel_e channels;
bitrate_e abr_bitrate;
bitrate_e cbr_bitrate;
int quality;
encode_mode_e enc_mode;
samplerate_e resample_frequency;
samplerate_e in_samplerate;
//The constructor; used to set default values
settings_t();
};
class CLameHelper; //lameHelper prototype, needed because of struct StaticParam_t
//Use to hold parameters for the thread function
struct StaticParam_t
{
char* pcm;
char* mp3;
settings_t settings;
WNDPROC callback_proc;
CLameHelper* lhObj;
};
class CLameHelper
{
public :
static const int PCM_SIZE = 4096;
static const int MP3_SIZE = 4096;
HANDLE m_hThread[MAX_THREAD_COUNT];
StaticParam_t* m_phSParam[MAX_THREAD_COUNT];
static int Decode_s(void* pParam);
void WriteWaveHeader(FILE* const, int, int, int, int);
void Write32BitLowHigh(FILE*, int);
void Write16BitLowHigh(FILE*, int);
int SetID3AlbumArt(lame_t gfp, char const* szFileName);
void errorHandler(char*);
char errMsg[1000];
public:
CLameHelper();
~CLameHelper();
int Decode(char* szMp3_in, char* szPcm_out);
int Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc);
};
#endif
CPP FILE
#include "stdafx.h"
#include "LameHelper.h"
settings_t::settings_t()
{
//Setting the default values
title = "";
artist = "";
album = "";
comment = "";
year = "";
track = "";
genre = "";
albumart = NULL;
channels = EC_STEREO;
abr_bitrate = BR_128kbps;
cbr_bitrate = BR_128kbps;
quality = 5;
enc_mode = EM_CBR;
resample_frequency = SR_44khz;
in_samplerate = SR_44khz;
}
CLameHelper::CLameHelper()
{
//Initialize to NULL, aids deletion/closing later
for(int i = 0; i < MAX_THREAD_COUNT; i++)
{
m_hThread[i] = NULL;
m_phSParam[i] = NULL;
}
}
CLameHelper::~CLameHelper()
{
//Destroy all declared objects
for(int i = 0; i < MAX_THREAD_COUNT; i++)
{
if(m_hThread[i] != NULL)
CloseHandle(m_hThread[i]);
if(m_phSParam[i] != NULL)
delete m_phSParam[i];
}
}
int CLameHelper::SetID3AlbumArt(lame_t gfp, char const* szFileName)
{
int iResult = -1;
FILE *pFileName = 0;
char *szAlbumart = 0;
if(szFileName == NULL)
{
return 0;
}
pFileName = fopen(szFileName, "rb");
if(!pFileName)
{
iResult = 1;
}
else
{
size_t size;
fseek(pFileName, 0, SEEK_END);
size = ftell(pFileName);
fseek(pFileName, 0, SEEK_SET);
szAlbumart = (char*)malloc(size);
if(!szAlbumart)
{
iResult = 2;
}
else
{
if(fread(szAlbumart, 1, size, pFileName) != size)
{
iResult = 3;
}
else
{
iResult = (gfp, szAlbumart, size) ? 4 : 0;
}
free(szAlbumart);
}
fclose(pFileName);
}
switch(iResult)
{
case 1:
sprintf(errMsg, "WARNING: could not find file '%s' for szAlbumart.\n", szFileName);
errorHandler(errMsg);
break;
case 2:
errorHandler("WARNING: insufficient memory for reading the szAlbumart.\n");
break;
case 3:
sprintf(errMsg, "WARNING: read error in '%s' for szAlbumart.\n", szFileName);
errorHandler(errMsg);
break;
case 4:
sprintf(errMsg, "WARNING: unsupported image: '%s' for szAlbumart. Specify JPEG/PNG/GIF image\n", szFileName);
errorHandler(errMsg);
break;
default:
break;
}
return iResult;
}
void CLameHelper::Write16BitLowHigh(FILE * fp, int val)
{
unsigned char bytes[2];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
fwrite(bytes, 1, 2, fp);
}
void CLameHelper::Write32BitLowHigh(FILE * fp, int val)
{
unsigned char bytes[4];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
bytes[2] = ((val >> 16) & 0xff);
bytes[3] = ((val >> 24) & 0xff);
fwrite(bytes, 1, 4, fp);
}
void CLameHelper::WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
int bytes = (bits + 7) / 8;
/* quick and dirty, but documented */
fwrite("RIFF", 1, 4, fp); /* label */
Write32BitLowHigh(fp, pcmbytes + 44 - 8); /* length in bytes without header */
fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
Write32BitLowHigh(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
Write16BitLowHigh(fp, 1); /* is PCM? */
Write16BitLowHigh(fp, channels); /* number of channels */
Write32BitLowHigh(fp, freq); /* sample frequency in [Hz] */
Write32BitLowHigh(fp, freq * channels * bytes); /* bytes per second */
Write16BitLowHigh(fp, channels * bytes); /* bytes per sample time */
Write16BitLowHigh(fp, bits); /* bits per sample */
fwrite("data", 1, 4, fp); /* label */
Write32BitLowHigh(fp, pcmbytes); /* length in bytes of raw PCM data */
}
int CLameHelper::Decode(char* szMp3_in, char* szPcm_out)
{
return Decode(szMp3_in, szPcm_out, NULL);
}
//the static function used for the thread
int CLameHelper::Decode_s(void* param)
{
StaticParam_t* sp = (StaticParam_t*)param;
char* szPcm_out = sp->pcm;
char* szMp3_in = sp->mp3;
WNDPROC callback_proc = sp->callback_proc;
CLameHelper* lh = (CLameHelper*)sp->lhObj;
return lh->Decode(szMp3_in, szPcm_out, callback_proc);
}
int CLameHelper::Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc)
{
int read, i, samples;
long wavsize = 0; // use to count the number of mp3 byte read, this is used to write the length of the wave file
long cumulative_read = 0;
short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
unsigned char mp3_buffer[MP3_SIZE];
FILE* mp3 = fopen(szMp3_in, "rb");
if(mp3 == NULL)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
}
sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for read. Aborting!\n", szMp3_in);
errorHandler(errMsg);
return -1;
}
fseek(mp3, 0, SEEK_END);
long MP3_total_size = ftell(mp3);
fseek(mp3, 0, SEEK_SET);
FILE* pcm = fopen(szPcm_out, "wb");
if(pcm == NULL)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
}
sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for write. Aborting!\n", szPcm_out);
errorHandler(errMsg);
return -1;
}
lame_t lame = lame_init();
lame_set_decode_only(lame, 1);
if(lame_init_params(lame) == -1)
{
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -2, NULL);
}
sprintf(errMsg, "FATAL ERROR: parameters failed to initialize properly in lame. Aborting!\n", szPcm_out);
errorHandler(errMsg);
return -2;
}
hip_t hip = hip_decode_init();
mp3data_struct mp3data;
memset(&mp3data, 0, sizeof(mp3data));
int nChannels = -1;
int nSampleRate = -1;
int mp3_len;
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_STARTED, NULL, NULL);
}
while((read = fread(mp3_buffer, sizeof(char), MP3_SIZE, mp3)) > 0)
{
mp3_len = read;
cumulative_read += read * sizeof(char);
do
{
samples = hip_decode1_headers(hip, mp3_buffer, mp3_len, pcm_l, pcm_r, &mp3data);
wavsize += samples;
if(mp3data.header_parsed == 1)//header is gotten
{
if(nChannels < 0)//reading for the first time
{
//Write the header
WriteWaveHeader(pcm, 0x7FFFFFFF, mp3data.samplerate, mp3data.stereo, 16); //unknown size, so write maximum 32 bit signed value
}
nChannels = mp3data.stereo;
nSampleRate = mp3data.samplerate;
}
if(samples > 0 && mp3data.header_parsed != 1)
{
errorHandler("WARNING: lame decode error occured!");
break;
}
if(samples > 0)
{
for(i = 0 ; i < samples; i++)
{
fwrite((char*)&pcm_l[i], sizeof(char), sizeof(pcm_l[i]), pcm);
if(nChannels == 2)
{
fwrite((char*)&pcm_r[i], sizeof(char), sizeof(pcm_r[i]), pcm);
}
}
}
mp3_len = 0;
if(callback_proc != NULL)
{
int percentage = ((float)cumulative_read/MP3_total_size)*100;
callback_proc((HWND)GetModuleHandle(NULL), LH_COMPUTED, percentage, NULL);
}
}while(samples>0);
}
i = (16 / 8) * mp3data.stereo;
if (wavsize <= 0)
{
wavsize = 0;
}
else if (wavsize > 0xFFFFFFD0 / i)
{
wavsize = 0xFFFFFFD0;
}
else
{
wavsize *= i;
}
if(!fseek(pcm, 0l, SEEK_SET))//seek back and adjust length
WriteWaveHeader(pcm, (int) wavsize, mp3data.samplerate, mp3data.stereo, 16);
else
errorHandler("WARNING: can't seek back to adjust length in wave header!");
hip_decode_exit(hip);
lame_close(lame);
fclose(mp3);
fclose(pcm);
if(callback_proc != NULL)
{
callback_proc((HWND)GetModuleHandle(NULL), LH_DONE, NULL, NULL);
}
return 0;
}
void CLameHelper::errorHandler(char* msg)
{
printf("%s\n", msg);
}
I'm in the process of working on a kernel program to handle printing capabilities of input for a custom OS. I'm following Poncho's 2nd YouTube Video series found here, I'm currently on Video 4 in the series where he starts to add numerical types as inputs to the renderer's print function. Now, my code isn't exactly like his as I made some modifications.
-Note- This won't compile directly as there is no main function. _start is being called or invoked by a bootloader that isn't shown here, I will however, add it to the bottom of this question.
When I use the class's print function like this within my kernel:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text");
renderer.Print('\n');
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And I run the kernel in emu. I'm getting the following output displayed:
This is some text
123456789
-123456789
The above is correct, however, when I try to incorporate the ability to parse a newline set of characters being either \n or \0 within of a const char* that acts as a string as seen in the following example:
#include "BasicRenderer.h"
extern "C" void _start(Framebuffer* framebuffer, PSF1_FONT** fonts) {
BasicRenderer = renderer(framebuffer, fonts);
renderer.Print("This is some text\n");
renderer.Print(uint64_t(123456789));
renderer.Print('\n');
renderer.Print(int64_t(-123456789));
return;
}
And now the displayed output is:
This is some text
123456789
-123456789
Here, the output in the second line has a space preceding the numerical value to be displayed after the call to Print() that has a \n within its string. I'm not sure what is causing this in my code. Does it have to do with the while condition or how I'm incrementing and indexing into the character string within BasicRenderer::Print(const char* str)? Or is it coming from BasicRender::PutChar(char c)? Or is it within one of the to_string() functions?
Here is the relevant implementation code...
BasicRenderer.cpp
#include "BasicRenderer.h"
void BasicRenderer::Print(const char* str) {
char* chr = (char*)str;
while(*chr != 0) {
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
} else {
PutChar(*chr);
cursor_position_.x += 8;
if (cursor_position_.x + 8 > framebuffer_->Width) {
cursor_position_.x = 0;
cursor_position_.y += 16;
}
chr++;
}
}
}
void BasicRenderer::Print(uint64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::Print(int64_t val) {
const char* str = to_string(val);
Print(str);
}
void BasicRenderer::PutChar(char c) {
if (c == '\n' || c == '\0') {
cursor_position_.x = 0;
cursor_position_.y += 16;
} else {
unsigned int* pixPtr = (unsigned int*)framebuffer_->BaseAddress;
char* fontPtr = (char*)selected_font_->glyphBuffer + (c * selected_font_->psf1_Header->charsize);
for (unsigned long y = cursor_position_.y; y < cursor_position_.y + 16; y++) {
for (unsigned long x = cursor_position_.x; x < cursor_position_.x + 8; x++) {
if ((*fontPtr & (0b10000000 >> (x - cursor_position_.x))) > 0) {
*(unsigned int*)(pixPtr + x + (y * framebuffer_->PixelsPerScanLine)) = font_color_;
}
}
fontPtr++;
}
}
}
cstr.cpp
#include "cstr.h"
const char* to_string(uint64_t value) {
static char output_uint_buffer[128];
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_uint_buffer[size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_uint_buffer[size-idx] = remainder + '0';
output_uint_buffer[size + 1] = 0;
return output_uint_buffer;
}
const char* to_string(int64_t value) {
static char output_int_buffer[128];
uint8_t isNegative = 0;
if (value < 0) {
isNegative = 1;
value *= -1;
output_int_buffer[0] = '-';
}
uint8_t size = 0;
uint64_t sizeTest = value;
while (sizeTest / 10 > 0) {
sizeTest /= 10;
size++;
}
uint8_t idx = 0;
while (value / 10 > 0) {
uint8_t remainder = value % 10;
value /= 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
idx++;
}
uint8_t remainder = value % 10;
output_int_buffer[isNegative + size - idx] = remainder + '0';
output_int_buffer[isNegative + size + 1] = 0;
return output_int_buffer;
}
And here is the rest of the declarations...
BasicRender.h
#pragma once
#include "cstr.h"
#include "math.h"
#include "framebuffer.h"
#include "SimpleFonts.h"
class BasicRenderer {
public:
BasicRenderer(Framebuffer* framebuffer, PSF1_FONT** fonts) :
framebuffer_{framebuffer},
fonts_{fonts},
cursor_position_({0,0}),
selected_font_{fonts_[0]},
font_color_{0xFFFFFFFF}
{}
void Print(const char* str);
void Print(char c) { PutChar(c); }
void Print(uint64_t val);
void Print(int64_t val);
private:
void PutChar(char c);
Framebuffer* framebuffer_;
Point cursor_position_;
PSF1_FONT** fonts_;
PSF1_FONT* selected_font_;
unsigned int font_color_;
};
cstr.h
#pragma once
#include <stdint.h>
const char* to_string(uint64_t value);
const char* to_string(int64_t value);
math.h
#pragma once
struct Point {
unsigned int x;
unsigned int y;
};
Framebuffer.h
#pragma once
#include <stddef.h>
struct Framebuffer {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
};
SimpleFonts.h
#pragma once
struct PSF1_HEADER {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
};
struct PSF1_FONT {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
};
Here is the bootloader application that invokes the above kernel.
main.c
#include <efi.h>
#include <efilib.h>
#include <elf.h>
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
typedef unsigned long long size_t;
typedef struct {
unsigned char magic[2];
unsigned char mode;
unsigned char charsize;
} PSF1_HEADER;
typedef struct {
PSF1_HEADER* psf1_Header;
void* glyphBuffer;
} PSF1_FONT;
typedef struct {
void* BaseAddress;
size_t BufferSize;
unsigned int Width;
unsigned int Height;
unsigned int PixelsPerScanLine;
} Framebuffer; Framebuffer framebuffer;
Framebuffer* InitializeGOP() {
EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
EFI_STATUS status;
status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void**)&gop);
if (EFI_ERROR(status)) {
Print(L"Unable to locate GOP\n\r");
return NULL;
} else {
Print(L"GOP located\n\r");
}
framebuffer.BaseAddress = (void*)gop->Mode->FrameBufferBase;
framebuffer.BufferSize = gop->Mode->FrameBufferSize;
framebuffer.Width = gop->Mode->Info->HorizontalResolution;
framebuffer.Height = gop->Mode->Info->VerticalResolution;
framebuffer.PixelsPerScanLine = gop->Mode->Info->PixelsPerScanLine;
return &framebuffer;
}
EFI_FILE* LoadFile(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* LoadedFile;
EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
SystemTable->BootServices->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (void**)&LoadedImage);
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem;
SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (void**)&FileSystem);
if (Directory == NULL) {
FileSystem->OpenVolume(FileSystem, &Directory);
}
EFI_STATUS s = Directory->Open(Directory, &LoadedFile, Path, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
if (s != EFI_SUCCESS) {
return NULL;
}
return LoadedFile;
}
PSF1_FONT* LoadPSF1Font(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
EFI_FILE* font = LoadFile(Directory, Path, ImageHandle, SystemTable);
if (font == NULL) return NULL;
PSF1_HEADER* fontHeader;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_HEADER), (void**)&fontHeader);
UINTN size = sizeof(PSF1_HEADER);
font->Read(font, &size, fontHeader);
if (fontHeader->magic[0] != PSF1_MAGIC0 || fontHeader->magic[1] != PSF1_MAGIC1) return NULL;
UINTN glyphBufferSize = fontHeader->charsize * 256;
if (fontHeader->mode == 1) { // 512 glyph mode
glyphBufferSize *= 2;
}
void* glyphBuffer;
font->SetPosition(font, sizeof(PSF1_HEADER));
SystemTable->BootServices->AllocatePool(EfiLoaderData, glyphBufferSize, (void**)&glyphBuffer);
font->Read(font, &glyphBufferSize, glyphBuffer);
PSF1_FONT* finishedFont;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(PSF1_FONT), (void**)&finishedFont);
finishedFont->psf1_Header = fontHeader;
finishedFont->glyphBuffer = glyphBuffer;
return finishedFont;
}
int memcmp(const void* aptr, const void* bptr, size_t n) {
const unsigned char* a = aptr, *b = bptr;
for (size_t i = 0; i < n; i++) {
if (a[i] < b[i]) return -1;
else if(a[i] > b[i]) return 1;
}
return 0;
}
EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
InitializeLib(ImageHandle, SystemTable);
Print(L"Hello World!\n\r");
EFI_FILE* Kernel = LoadFile(NULL, L"kernel.elf", ImageHandle, SystemTable);
if ( Kernel == NULL) {
Print(L"Could not load kernel \n\r");
} else {
Print(L"Kernel Loaded Successfully \n\r");
}
Elf64_Ehdr header;
{
UINTN FileInfoSize;
EFI_FILE_INFO* FileInfo;
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, NULL);
SystemTable->BootServices->AllocatePool(EfiLoaderData, FileInfoSize, (void**)&FileInfo);
Kernel->GetInfo(Kernel, &gEfiFileInfoGuid, &FileInfoSize, (void**)&FileInfo);
UINTN size = sizeof(header);
Kernel->Read(Kernel, &size, &header);
}
if (
memcmp(&header.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 ||
header.e_ident[EI_CLASS] != ELFCLASS64 ||
header.e_ident[EI_DATA] != ELFDATA2LSB ||
header.e_type != ET_EXEC ||
header.e_machine != EM_X86_64 ||
header.e_version != EV_CURRENT
) {
Print(L"kernel format is bad\r\n");
} else {
Print(L"kernel header successfully verified\r\n");
}
Elf64_Phdr* phdrs;
{
Kernel->SetPosition(Kernel, header.e_phoff);
UINTN size = header.e_phnum * header.e_phentsize;
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&phdrs);
Kernel->Read(Kernel, &size, phdrs);
}
for (
Elf64_Phdr* phdr = phdrs;
(char*)phdr < (char*)phdrs + header.e_phnum * header.e_phentsize;
phdr = (Elf64_Phdr*)((char*)phdr + header.e_phentsize)
) {
switch(phdr->p_type) {
case PT_LOAD: {
int pages = (phdr->p_memsz + 0x1000 - 1) / 0x1000;
Elf64_Addr segment = phdr->p_paddr;
SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, pages, &segment);
Kernel->SetPosition(Kernel, phdr->p_offset);
UINTN size = phdr->p_filesz;
Kernel->Read(Kernel, &size, (void*)segment);
break;
}
}
}
Print(L"Kernel Loaded\n\r");
void (*KernelStart)(Framebuffer*, PSF1_FONT**) = ((__attribute__((sysv_abi)) void(*)(Framebuffer*, PSF1_FONT**) ) header.e_entry);
PSF1_FONT* newFont = LoadPSF1Font(NULL, L"zap-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* newFontExt = LoadPSF1Font(NULL, L"zap-ext-light16.psf", ImageHandle, SystemTable);
if (newFont == NULL) {
Print(L"Font is not valid or is not found\n\r");
} else {
Print(L"Font found, char size = %d\n\r", newFont->psf1_Header->charsize);
}
PSF1_FONT* fonts[] = {newFont, newFontExt};
Framebuffer* newBuffer = InitializeGOP();
Print(L"Base: 0x%x\n\rSize: 0x%x\n\rWidth: %d\n\rHeight: %d\n\rPixelsPerScanline: %d\n\r",
newBuffer->BaseAddress,
newBuffer->BufferSize,
newBuffer->Width,
newBuffer->Height,
newBuffer->PixelsPerScanLine);
KernelStart(newBuffer, fonts);
return EFI_SUCCESS; // Exit the UEFI application
}
The problem is here:
if ( (*chr == '\\') && ((*chr+1 == 'n') || (*chr+1 == '0')) ) {
PutChar('\n');
chr++;
chr++;
}
...
You should not be parsing out \n since this will be present in the string as a linefeed character. What you want instead is:
if (*chr == '\n') {
PutChar('\n');
chr++;
}
...
How do you copy one stream to another using dedicated read/write threads in C++?
Let's say I have these methods (not real, but to illustrate the point) to read/write data from. These read/write functions could represent anything (network/file/USB/serial/etc).
// returns the number of bytes read
void read(char* buffer, int bufferSize, int* bytesRead);
// returns the number of bytes written
void write(char* buffer, int bufferSize, int* bytesWritten);
The solution should also be portable.
NOTE: I am aware that Windows has a FILE_FLAG_OVERLAPPED feature, but this assumes that the read/write is file IO. Remember, these read/write methods could represent anything.
Here is the solution I came up with.
Header
#pragma once
#include <stdlib.h>
#include <queue>
#include <mutex>
#include <thread>
#include <chrono>
#include <list>
#include <thread>
#define ASYNC_COPY_READ_WRITE_SUCCESS 0
struct BufferBlock;
struct ReadStream
{
// read a stream to a buffer.
// return non-zero if error occured
virtual int read(char* buffer, int bufferSize, int* bytesRead) = 0;
};
struct WriteStream
{
// write a buffer to a stream.
// return non-zero if error occured
virtual int write(char* buffer, int bufferSize, int* bytesWritten) = 0;
};
class BufferBlockManager
{
public:
BufferBlockManager(int numberOfBlocks, int bufferSize);
~BufferBlockManager();
void enqueueBlockForRead(BufferBlock* block);
void dequeueBlockForRead(BufferBlock** block);
void enqueueBlockForWrite(BufferBlock* block);
void dequeueBlockForWrite(BufferBlock** block);
void resetState();
private:
std::list<BufferBlock*> blocks;
std::queue<BufferBlock*> blocksPendingRead;
std::queue<BufferBlock*> blocksPendingWrite;
std::mutex queueLock;
std::chrono::milliseconds dequeueSleepTime;
};
void AsyncCopyStream(BufferBlockManager* bufferBlockManager, ReadStream* readStream, WriteStream* writeStream, int* readResult, int* writeResult);
CPP
#include "AsyncReadWrite.h"
struct BufferBlock
{
BufferBlock(int bufferSize) : buffer(NULL)
{
this->bufferSize = bufferSize;
this->buffer = new char[bufferSize];
this->actualSize = 0;
this->isLastBlock = false;
}
~BufferBlock()
{
this->bufferSize = 0;
free(this->buffer);
this->buffer = NULL;
this->actualSize = 0;
}
char* buffer;
int bufferSize;
int actualSize;
bool isLastBlock;
};
BufferBlockManager::BufferBlockManager(int numberOfBlocks, int bufferSize)
{
dequeueSleepTime = std::chrono::milliseconds(100);
for (int x = 0; x < numberOfBlocks; x++)
{
BufferBlock* block = new BufferBlock(bufferSize);
blocks.push_front(block);
blocksPendingRead.push(block);
}
}
BufferBlockManager::~BufferBlockManager()
{
for (std::list<BufferBlock*>::const_iterator iterator = blocks.begin(), end = blocks.end(); iterator != end; ++iterator) {
delete (*iterator);
}
}
void BufferBlockManager::enqueueBlockForRead(BufferBlock* block)
{
queueLock.lock();
block->actualSize = 0;
block->isLastBlock = false;
blocksPendingRead.push(block);
queueLock.unlock();
}
void BufferBlockManager::dequeueBlockForRead(BufferBlock** block)
{
WAITFOR:
while (blocksPendingRead.size() == 0)
std::this_thread::sleep_for(dequeueSleepTime);
queueLock.lock();
if (blocksPendingRead.size() == 0)
{
queueLock.unlock();
goto WAITFOR;
}
*block = blocksPendingRead.front();
blocksPendingRead.pop();
queueLock.unlock();
}
void BufferBlockManager::enqueueBlockForWrite(BufferBlock* block)
{
queueLock.lock();
blocksPendingWrite.push(block);
queueLock.unlock();
}
void BufferBlockManager::dequeueBlockForWrite(BufferBlock** block)
{
WAITFOR:
while (blocksPendingWrite.size() == 0)
std::this_thread::sleep_for(dequeueSleepTime);
queueLock.lock();
if (blocksPendingWrite.size() == 0)
{
queueLock.unlock();
goto WAITFOR;
}
*block = blocksPendingWrite.front();
blocksPendingWrite.pop();
queueLock.unlock();
}
void BufferBlockManager::resetState()
{
queueLock.lock();
blocksPendingRead = std::queue<BufferBlock*>();
blocksPendingWrite = std::queue<BufferBlock*>();
for (std::list<BufferBlock*>::const_iterator iterator = blocks.begin(), end = blocks.end(); iterator != end; ++iterator) {
(*iterator)->actualSize = 0;
}
queueLock.unlock();
}
struct AsyncCopyContext
{
AsyncCopyContext(BufferBlockManager* bufferBlockManager, ReadStream* readStream, WriteStream* writeStream)
{
this->bufferBlockManager = bufferBlockManager;
this->readStream = readStream;
this->writeStream = writeStream;
this->readResult = ASYNC_COPY_READ_WRITE_SUCCESS;
this->writeResult = ASYNC_COPY_READ_WRITE_SUCCESS;
}
BufferBlockManager* bufferBlockManager;
ReadStream* readStream;
WriteStream* writeStream;
int readResult;
int writeResult;
};
void ReadStreamThread(AsyncCopyContext* asyncContext)
{
int bytesRead = 0;
BufferBlock* readBuffer = NULL;
int readResult = ASYNC_COPY_READ_WRITE_SUCCESS;
while (
// as long there hasn't been any write errors
asyncContext->writeResult == ASYNC_COPY_READ_WRITE_SUCCESS
// and we haven't had an error reading yet
&& readResult == ASYNC_COPY_READ_WRITE_SUCCESS)
{
// let's deque a block to read to!
asyncContext->bufferBlockManager->dequeueBlockForRead(&readBuffer);
readResult = asyncContext->readStream->read(readBuffer->buffer, readBuffer->bufferSize, &bytesRead);
readBuffer->actualSize = bytesRead;
readBuffer->isLastBlock = bytesRead == 0;
if (readResult == ASYNC_COPY_READ_WRITE_SUCCESS)
{
// this was a valid read, go ahead and queue it for writing
asyncContext->bufferBlockManager->enqueueBlockForWrite(readBuffer);
}
else
{
// an error occured reading
asyncContext->readResult = readResult;
// since an error occured, lets queue an block to write indicatiting we are done and there are no more bytes to read
readBuffer->isLastBlock = true;
readBuffer->actualSize = 0;
asyncContext->bufferBlockManager->enqueueBlockForWrite(readBuffer);
}
if (readBuffer->isLastBlock) return;
}
}
void WriteStreamThread(AsyncCopyContext* asyncContext)
{
int bytesWritten = 0;
BufferBlock* writeBuffer = NULL;
int writeResult = ASYNC_COPY_READ_WRITE_SUCCESS;
bool isLastWriteBlock = false;
while (
// as long as there are no errors during reading
asyncContext->readResult == ASYNC_COPY_READ_WRITE_SUCCESS
// and we haven't had an error writing yet
&& writeResult == ASYNC_COPY_READ_WRITE_SUCCESS)
{
// lets dequeue a block for writing!
asyncContext->bufferBlockManager->dequeueBlockForWrite(&writeBuffer);
isLastWriteBlock = writeBuffer->isLastBlock;
if (writeBuffer->actualSize > 0)
writeResult = asyncContext->writeStream->write(writeBuffer->buffer, writeBuffer->actualSize, &bytesWritten);
if (writeResult == ASYNC_COPY_READ_WRITE_SUCCESS)
{
asyncContext->bufferBlockManager->enqueueBlockForRead(writeBuffer);
if (isLastWriteBlock) return;
}
else
{
asyncContext->writeResult = writeResult;
asyncContext->bufferBlockManager->enqueueBlockForRead(writeBuffer);
return;
}
}
}
void AsyncCopyStream(BufferBlockManager* bufferBlockManager, ReadStream* readStream, WriteStream* writeStream, int* readResult, int* writeResult)
{
AsyncCopyContext asyncContext(bufferBlockManager, readStream, writeStream);
std::thread readThread(ReadStreamThread, &asyncContext);
std::thread writeThread(WriteStreamThread, &asyncContext);
readThread.join();
writeThread.join();
*readResult = asyncContext.readResult;
*writeResult = asyncContext.writeResult;
}
Usage
#include <stdio.h>
#include <tchar.h>
#include "AsyncReadWrite.h"
struct ReadTestStream : ReadStream
{
int readCount = 0;
int read(char* buffer, int bufferSize, int* bytesRead)
{
printf("Starting read...\n");
memset(buffer, bufferSize, 0);
if (readCount == 10)
{
*bytesRead = 0;
return 0;
}
// pretend this function takes a while!
std::this_thread::sleep_for(std::chrono::milliseconds(100));
char buff[100];
sprintf_s(buff, "This is read number %d\n", readCount);
strcpy_s(buffer, sizeof(buff), buff);
*bytesRead = strlen(buffer);
readCount++;
printf("Finished read...\n");
return 0;
}
};
struct WriteTestStream : WriteStream
{
int write(char* buffer, int bufferSize, int* bytesWritten)
{
printf("Starting write...\n");
// pretend this function takes a while!
std::this_thread::sleep_for(std::chrono::milliseconds(500));
printf(buffer);
printf("Finished write...\n");
return 0;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
BufferBlockManager bufferBlockManager(5, 4096);
ReadTestStream readStream;
WriteTestStream writeStream;
int readResult = 0;
int writeResult = 0;
printf("Starting copy...\n");
AsyncCopyStream(&bufferBlockManager, &readStream, &writeStream, &readResult, &writeResult);
printf("Finished copy... readResult=%d writeResult=%d \n", readResult, writeResult);
getchar();
return 0;
}
EDIT: I put my solution into a GitHub repository here. If you wish to use this code, refer to the repository since it may be more updated than this answer.
Typically, you would just have one thread for each direction that alternates between reads and writes.
I am trying to write a function which will change all RGB(255,0,0) pixels to RGB(255,0,255) but it doesn't seem to work :D Could anyone tell me the reason why it doesn't work/show me the right way to do it. All criticism all appreciated.
Here is part of my code:
#include <stdio.h>
#include <Windows.h>
#include <stdint.h>
struct BmpSignature
{
unsigned char data[2];
};
#pragma pack(1)
struct BmpHeader
{
BmpSignature signature;
uint32_t fileSize;
uint16_t reserved1;
uint16_t reserved2;
uint32_t dataOffset;
};
struct BmpDib
{
uint32_t dibSize;
int32_t imageWidth;
int32_t imageHeight;
uint16_t colorPlaneCount;
uint16_t pixelSize;
uint32_t compressMethod;
uint32_t bitmapByteCount;
int32_t horizontalResolution;
int32_t verticalResolution;
uint32_t colorCount;
uint32_t importantColorCount;
};
struct Color
{
unsigned char blue;
unsigned char green;
unsigned char red;
};
struct PixelArray
{
Color **pixels;
uint32_t rowCount;
uint32_t columnCount;
};
void changeBmp(PixelArray &p)
{
for (int i = 0; i < p.rowCount; i++)
for (int j = 0; j < p.columnCount; j++)
{
if (p.pixels[i][j].red == 255 && p.pixels[i][j].green == 0 && p.pixels[i][j].blue == 0)
{
p.pixels[i][j].blue = 255;
}
}
}
void readBmpPixelArray(FILE *f, BmpHeader header, BmpDib dib, PixelArray &data)
{
if (f == NULL)
return;
data.rowCount = dib.imageHeight;
data.columnCount = dib.imageWidth;
data.pixels = new Color*[data.rowCount];
char paddingCount = (4 - (dib.imageWidth * (dib.pixelSize / 8) % 4)) % 4;
fseek(f, header.dataOffset, 0L);
for (int i = 0; i < data.rowCount; i++)
{
scanBmpPixelLine(f, data.pixels[data.rowCount - i - 1], dib.imageWidth);
skipBmpPadding(f, paddingCount);
}
}
void writeBmpPixelArray(FILE *f, BmpHeader header, BmpDib dib, PixelArray &data)
{
if (f == NULL)
return;
data.rowCount = dib.imageHeight;
data.columnCount = dib.imageWidth;
char paddingCount = (4 - (dib.imageWidth * (dib.pixelSize / 8) % 4)) % 4;
fseek(f, header.dataOffset, 0L);
for (int i = 0; i < data.rowCount; i++)
{
writeBmpPixelLine(f, data.pixels[data.rowCount - i - 1], dib.imageWidth);
addBmpPadding(f, paddingCount);
}
}
void writeBmpPixelLine(FILE *f, Color *&line, uint32_t length)
{
if (f == NULL)
return;
fwrite(line, sizeof(Color), length, f);
}
void scanBmpPixelLine(FILE *f, Color *&line, uint32_t length)
{
if (f == NULL)
return;
line = new Color[length];
fread(line, sizeof(Color), length, f);
}
void addBmpPadding(FILE *f, char count)
{
if (f == NULL)
return;
if (count == 0)
return;
char padding[3];
fwrite(padding, count, 1, f);
}
void skipBmpPadding(FILE *f, char count)
{
if (f == NULL)
return;
if (count == 0)
return;
char padding[3];
fread(padding, count, 1, f);
}
void drawBmp(BmpDib dib, PixelArray data)
{
HWND console = GetConsoleWindow();
HDC hdc = GetDC(console);
for (int i = 0; i < dib.imageHeight; i++)
for (int j = 0; j < dib.imageWidth; j++)
{
Color pixel = data.pixels[i][j];
SetPixel(hdc, j, i, RGB(pixel.red, pixel.green, pixel.blue));
}
ReleaseDC(console, hdc);
}
void releaseBmpPixelArray(PixelArray data)
{
for (int i = 0; i < data.rowCount; i++)
delete[]data.pixels[i];
delete[]data.pixels;
}
int main()
{
BmpHeader header;
BmpDib info;
PixelArray data;
FILE * inputBMP;
inputBMP = fopen("D:\\Projects\\bitmap\\yoyo.bmp", "rb");
readBmpHeader(inputBMP, header);
printBmpHeader(header);
readBmpDib(inputBMP, info);
printBmpDib(info);
readBmpPixelArray(inputBMP, header, info, data);
HWND console = GetConsoleWindow();
if (console != NULL){ MoveWindow(console, 0, 0, 800, 600, TRUE); }
changeBmp(data);
drawBmp(info, data);
releaseBmpPixelArray(data);
fclose(inputBMP);
Sleep(100);
return 0;
}
i have difficulties in using LZMA SDK in my application.
I would like to create a kind of single file compression tool. I dont need any directory support, just need only the LZMA2 stream. But i have no idea on how LZMA SDK is to be used for this.
Please can anyone give me a little example on how the LZMA SDK can be used under C++?
I think that it's a properly little example to use LZMA SDK.
/* LzmaUtil.c -- Test application for LZMA compression
2008-08-05
Igor Pavlov
public domain */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LzmaDec.h"
#include "../LzmaEnc.h"
#include "../Alloc.h"
const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file";
const char *kCantAllocateMessage = "Can not allocate memory";
const char *kDataErrorMessage = "Data error";
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
#define kInBufferSize (1 << 15)
#define kOutBufferSize (1 << 15)
unsigned char g_InBuffer[kInBufferSize];
unsigned char g_OutBuffer[kOutBufferSize];
size_t MyReadFile(FILE *file, void *data, size_t size)
{ return fread(data, 1, size, file); }
int MyReadFileAndCheck(FILE *file, void *data, size_t size)
{ return (MyReadFile(file, data, size) == size); }
size_t MyWriteFile(FILE *file, const void *data, size_t size)
{
if (size == 0)
return 0;
return fwrite(data, 1, size, file);
}
int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
{ return (MyWriteFile(file, data, size) == size); }
long MyGetFileLength(FILE *file)
{
long length;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
void PrintHelp(char *buffer)
{
strcat(buffer, "\nLZMA Utility 4.58 Copyright (c) 1999-2008 Igor Pavlov 2008-04-11\n"
"\nUsage: lzma <e|d> inputFile outputFile\n"
" e: encode file\n"
" d: decode file\n");
}
int PrintError(char *buffer, const char *message)
{
strcat(buffer, "\nError: ");
strcat(buffer, message);
strcat(buffer, "\n");
return 1;
}
int PrintErrorNumber(char *buffer, SRes val)
{
sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
return 1;
}
int PrintUserError(char *buffer)
{
return PrintError(buffer, "Incorrect command");
}
#define IN_BUF_SIZE (1 << 16)
#define OUT_BUF_SIZE (1 << 16)
static int Decode(FILE *inFile, FILE *outFile, char *rs)
{
UInt64 unpackSize;
int thereIsSize; /* = 1, if there is uncompressed size in headers */
int i;
int res = 0;
CLzmaDec state;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
if (!MyReadFileAndCheck(inFile, header, sizeof(header)))
return PrintError(rs, kCantReadMessage);
unpackSize = 0;
thereIsSize = 0;
for (i = 0; i < 8; i++)
{
unsigned char b = header[LZMA_PROPS_SIZE + i];
if (b != 0xFF)
thereIsSize = 1;
unpackSize += (UInt64)b << (i * 8);
}
LzmaDec_Construct(&state);
res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
if (res != SZ_OK)
return res;
{
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
size_t inPos = 0, inSize = 0, outPos = 0;
LzmaDec_Init(&state);
for (;;)
{
if (inPos == inSize)
{
inSize = MyReadFile(inFile, inBuf, IN_BUF_SIZE);
inPos = 0;
}
{
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(&state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += (UInt32)inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outFile != 0)
MyWriteFile(outFile, outBuf, outPos);
outPos = 0;
if (res != SZ_OK || thereIsSize && unpackSize == 0)
break;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
res = SZ_ERROR_DATA;
break;
}
}
}
}
LzmaDec_Free(&state, &g_Alloc);
return res;
}
typedef struct _CFileSeqInStream
{
ISeqInStream funcTable;
FILE *file;
} CFileSeqInStream;
static SRes MyRead(void *p, void *buf, size_t *size)
{
if (*size == 0)
return SZ_OK;
*size = MyReadFile(((CFileSeqInStream*)p)->file, buf, *size);
/*
if (*size == 0)
return SZE_FAIL;
*/
return SZ_OK;
}
typedef struct _CFileSeqOutStream
{
ISeqOutStream funcTable;
FILE *file;
} CFileSeqOutStream;
static size_t MyWrite(void *pp, const void *buf, size_t size)
{
return MyWriteFile(((CFileSeqOutStream *)pp)->file, buf, size);
}
static SRes Encode(FILE *inFile, FILE *outFile, char *rs)
{
CLzmaEncHandle enc;
SRes res;
CFileSeqInStream inStream;
CFileSeqOutStream outStream;
CLzmaEncProps props;
enc = LzmaEnc_Create(&g_Alloc);
if (enc == 0)
return SZ_ERROR_MEM;
inStream.funcTable.Read = MyRead;
inStream.file = inFile;
outStream.funcTable.Write = MyWrite;
outStream.file = outFile;
LzmaEncProps_Init(&props);
res = LzmaEnc_SetProps(enc, &props);
if (res == SZ_OK)
{
Byte header[LZMA_PROPS_SIZE + 8];
size_t headerSize = LZMA_PROPS_SIZE;
UInt64 fileSize;
int i;
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
fileSize = MyGetFileLength(inFile);
for (i = 0; i < 8; i++)
header[headerSize++] = (Byte)(fileSize >> (8 * i));
if (!MyWriteFileAndCheck(outFile, header, headerSize))
return PrintError(rs, "writing error");
if (res == SZ_OK)
res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
NULL, &g_Alloc, &g_Alloc);
}
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
return res;
}
int main2(int numArgs, const char *args[], char *rs)
{
FILE *inFile = 0;
FILE *outFile = 0;
char c;
int res;
int encodeMode;
if (numArgs == 1)
{
PrintHelp(rs);
return 0;
}
if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
return PrintUserError(rs);
c = args[1][0];
encodeMode = (c == 'e' || c == 'E');
if (!encodeMode && c != 'd' && c != 'D')
return PrintUserError(rs);
{
size_t t4 = sizeof(UInt32);
size_t t8 = sizeof(UInt64);
if (t4 != 4 || t8 != 8)
return PrintError(rs, "LZMA UTil needs correct UInt32 and UInt64");
}
inFile = fopen(args[2], "rb");
if (inFile == 0)
return PrintError(rs, "Can not open input file");
if (numArgs > 3)
{
outFile = fopen(args[3], "wb+");
if (outFile == 0)
return PrintError(rs, "Can not open output file");
}
else if (encodeMode)
PrintUserError(rs);
if (encodeMode)
{
res = Encode(inFile, outFile, rs);
}
else
{
res = Decode(inFile, outFile, rs);
}
if (outFile != 0)
fclose(outFile);
fclose(inFile);
if (res != SZ_OK)
{
if (res == SZ_ERROR_MEM)
return PrintError(rs, kCantAllocateMessage);
else if (res == SZ_ERROR_DATA)
return PrintError(rs, kDataErrorMessage);
else
return PrintErrorNumber(rs, res);
}
return 0;
}
int MY_CDECL main(int numArgs, const char *args[])
{
char rs[800] = { 0 };
int res = main2(numArgs, args, rs);
printf(rs);
return res;
}
Also you can see it at:
http://read.pudn.com/downloads151/sourcecode/zip/656407/7z460/C/LzmaUtil/LzmaUtil.c__.htm
http://read.pudn.com/downloads157/sourcecode/zip/698262/LZMA/LzmaUtil.c__.htm
I recently found a nice example, written in C++. Credit goes to GH user Treeki who published the original gist:
// note: -D_7ZIP_ST is required when compiling on non-Windows platforms
// g++ -o lzma_sample -std=c++14 -D_7ZIP_ST lzma_sample.cpp LzmaDec.c LzmaEnc.c LzFind.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include "LzmaEnc.h"
#include "LzmaDec.h"
static void *_lzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void _lzmaFree(ISzAllocPtr, void *addr) {
if (!addr)
return;
delete[] reinterpret_cast<uint8_t *>(addr);
}
static ISzAlloc _allocFuncs = {
_lzmaAlloc, _lzmaFree
};
std::unique_ptr<uint8_t[]> lzmaCompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
std::unique_ptr<uint8_t[]> result;
// set up properties
CLzmaEncProps props;
LzmaEncProps_Init(&props);
if (inputSize >= (1 << 20))
props.dictSize = 1 << 20; // 1mb dictionary
else
props.dictSize = inputSize; // smaller dictionary = faster!
props.fb = 40;
// prepare space for the encoded properties
SizeT propsSize = 5;
uint8_t propsEncoded[5];
// allocate some space for the compression output
// this is way more than necessary in most cases...
// but better safe than sorry
// (a smarter implementation would use a growing buffer,
// but this requires a bunch of fuckery that is out of
/// scope for this simple example)
SizeT outputSize64 = inputSize * 1.5;
if (outputSize64 < 1024)
outputSize64 = 1024;
auto output = std::make_unique<uint8_t[]>(outputSize64);
int lzmaStatus = LzmaEncode(
output.get(), &outputSize64, input, inputSize,
&props, propsEncoded, &propsSize, 0,
NULL,
&_allocFuncs, &_allocFuncs);
*outputSize = outputSize64 + 13;
if (lzmaStatus == SZ_OK) {
// tricky: we have to generate the LZMA header
// 5 bytes properties + 8 byte uncompressed size
result = std::make_unique<uint8_t[]>(outputSize64 + 13);
uint8_t *resultData = result.get();
memcpy(resultData, propsEncoded, 5);
for (int i = 0; i < 8; i++)
resultData[5 + i] = (inputSize >> (i * 8)) & 0xFF;
memcpy(resultData + 13, output.get(), outputSize64);
}
return result;
}
std::unique_ptr<uint8_t[]> lzmaDecompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
if (inputSize < 13)
return NULL; // invalid header!
// extract the size from the header
UInt64 size = 0;
for (int i = 0; i < 8; i++)
size |= (input[5 + i] << (i * 8));
if (size <= (256 * 1024 * 1024)) {
auto blob = std::make_unique<uint8_t[]>(size);
ELzmaStatus lzmaStatus;
SizeT procOutSize = size, procInSize = inputSize - 13;
int status = LzmaDecode(blob.get(), &procOutSize, &input[13], &procInSize, input, 5, LZMA_FINISH_END, &lzmaStatus, &_allocFuncs);
if (status == SZ_OK && procOutSize == size) {
*outputSize = size;
return blob;
}
}
return NULL;
}
void hexdump(const uint8_t *buf, int size) {
int lines = (size + 15) / 16;
for (int i = 0; i < lines; i++) {
printf("%08x | ", i * 16);
int lineMin = i * 16;
int lineMax = lineMin + 16;
int lineCappedMax = (lineMax > size) ? size : lineMax;
for (int j = lineMin; j < lineCappedMax; j++)
printf("%02x ", buf[j]);
for (int j = lineCappedMax; j < lineMax; j++)
printf(" ");
printf("| ");
for (int j = lineMin; j < lineCappedMax; j++) {
if (buf[j] >= 32 && buf[j] <= 127)
printf("%c", buf[j]);
else
printf(".");
}
printf("\n");
}
}
void testIt(const uint8_t *input, int size) {
printf("Test Input:\n");
hexdump(input, size);
uint32_t compressedSize;
auto compressedBlob = lzmaCompress(input, size, &compressedSize);
if (compressedBlob) {
printf("Compressed:\n");
hexdump(compressedBlob.get(), compressedSize);
} else {
printf("Nope, we screwed it\n");
return;
}
// let's try decompressing it now
uint32_t decompressedSize;
auto decompressedBlob = lzmaDecompress(compressedBlob.get(), compressedSize, &decompressedSize);
if (decompressedBlob) {
printf("Decompressed:\n");
hexdump(decompressedBlob.get(), decompressedSize);
} else {
printf("Nope, we screwed it (part 2)\n");
return;
}
printf("----------\n");
}
void testIt(const char *string) {
testIt((const uint8_t *)string, strlen(string));
}
int main(int argc, char **argv) {
testIt("a");
testIt("here is a cool string");
testIt("here's something that should compress pretty well: abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef");
return 0;
}
You can refer to this file on how to use lzma2。
https://github.com/Tencent/libpag/blob/aab6391e455193c8ec5b8e2031b495b3fe77b034/test/framework/utils/LzmaUtil.cpp
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making libpag available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#include "LzmaUtil.h"
#include "test/framework/lzma/Lzma2DecMt.h"
#include "test/framework/lzma/Lzma2Enc.h"
namespace pag {
static void* LzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void LzmaFree(ISzAllocPtr, void* address) {
if (!address) {
return;
}
delete[] reinterpret_cast<uint8_t*>(address);
}
static ISzAlloc gAllocFuncs = {LzmaAlloc, LzmaFree};
class SequentialOutStream {
public:
virtual ~SequentialOutStream() = default;
virtual bool write(const void* data, size_t size) = 0;
};
class SequentialInStream {
public:
virtual ~SequentialInStream() = default;
virtual bool read(void* data, size_t size, size_t* processedSize) = 0;
};
struct CSeqInStreamWrap {
ISeqInStream vt;
std::unique_ptr<SequentialInStream> inStream;
};
struct CSeqOutStreamWrap {
ISeqOutStream vt;
std::unique_ptr<SequentialOutStream> outStream;
};
class BuffPtrInStream : public SequentialInStream {
public:
explicit BuffPtrInStream(const uint8_t* buffer, size_t bufferSize)
: buffer(buffer), bufferSize(bufferSize) {
}
bool read(void* data, size_t size, size_t* processedSize) override {
if (processedSize) {
*processedSize = 0;
}
if (size == 0 || position >= bufferSize) {
return true;
}
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
memcpy(data, static_cast<const uint8_t*>(buffer) + position, remain);
position += remain;
if (processedSize) {
*processedSize = remain;
}
return true;
}
private:
const uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
class VectorOutStream : public SequentialOutStream {
public:
explicit VectorOutStream(std::vector<uint8_t>* buffer) : buffer(buffer) {
}
bool write(const void* data, size_t size) override {
auto oldSize = buffer->size();
buffer->resize(oldSize + size);
memcpy(&(*buffer)[oldSize], data, size);
return true;
}
private:
std::vector<uint8_t>* buffer;
};
class BuffPtrSeqOutStream : public SequentialOutStream {
public:
BuffPtrSeqOutStream(uint8_t* buffer, size_t size) : buffer(buffer), bufferSize(size) {
}
bool write(const void* data, size_t size) override {
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
if (remain != 0) {
memcpy(buffer + position, data, remain);
position += remain;
}
return remain != 0 || size == 0;
}
private:
uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
static const size_t kStreamStepSize = 1 << 31;
static SRes MyRead(const ISeqInStream* p, void* data, size_t* size) {
CSeqInStreamWrap* wrap = CONTAINER_FROM_VTBL(p, CSeqInStreamWrap, vt);
auto curSize = (*size < kStreamStepSize) ? *size : kStreamStepSize;
if (!wrap->inStream->read(data, curSize, &curSize)) {
return SZ_ERROR_READ;
}
*size = curSize;
return SZ_OK;
}
static size_t MyWrite(const ISeqOutStream* p, const void* buf, size_t size) {
auto* wrap = CONTAINER_FROM_VTBL(p, CSeqOutStreamWrap, vt);
if (wrap->outStream->write(buf, size)) {
return size;
}
return 0;
}
class Lzma2Encoder {
public:
Lzma2Encoder() {
encoder = Lzma2Enc_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Encoder() {
Lzma2Enc_Destroy(encoder);
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (encoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto inputSize = inputData->size();
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.dictSize = inputSize;
lzma2Props.lzmaProps.level = 9;
lzma2Props.numTotalThreads = 4;
Lzma2Enc_SetProps(encoder, &lzma2Props);
std::vector<uint8_t> outBuf;
outBuf.resize(1 + 8);
outBuf[0] = Lzma2Enc_WriteProperties(encoder);
for (int i = 0; i < 8; i++) {
outBuf[1 + i] = static_cast<uint8_t>(inputSize >> (8 * i));
}
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(
static_cast<const uint8_t*>(inputData->data()), inputSize);
CSeqOutStreamWrap outStream = {};
outStream.vt.Write = MyWrite;
outStream.outStream = std::make_unique<VectorOutStream>(&outBuf);
auto status =
Lzma2Enc_Encode2(encoder, &outStream.vt, nullptr, nullptr, &inWrap.vt, nullptr, 0, nullptr);
if (status != SZ_OK) {
return nullptr;
}
return Data::MakeWithCopy(&outBuf[0], outBuf.size());
}
private:
CLzma2EncHandle encoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Compress(const std::shared_ptr<Data>& pixelData) {
Lzma2Encoder encoder;
return encoder.code(pixelData);
}
class Lzma2Decoder {
public:
Lzma2Decoder() {
decoder = Lzma2DecMt_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Decoder() {
if (decoder) {
Lzma2DecMt_Destroy(decoder);
}
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (decoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto input = static_cast<const uint8_t*>(inputData->data());
auto inputSize = inputData->size() - 9;
Byte prop = static_cast<const Byte*>(input)[0];
CLzma2DecMtProps props;
Lzma2DecMtProps_Init(&props);
props.inBufSize_ST = inputSize;
props.numThreads = 1;
UInt64 outBufferSize = 0;
for (int i = 0; i < 8; i++) {
outBufferSize |= (input[1 + i] << (i * 8));
}
auto outBuffer = new uint8_t[outBufferSize];
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(input + 9, inputSize);
CSeqOutStreamWrap outWrap = {};
outWrap.vt.Write = MyWrite;
outWrap.outStream = std::make_unique<BuffPtrSeqOutStream>(outBuffer, outBufferSize);
UInt64 inProcessed = 0;
int isMT = false;
auto res = Lzma2DecMt_Decode(decoder, prop, &props, &outWrap.vt, &outBufferSize, 1, &inWrap.vt,
&inProcessed, &isMT, nullptr);
if (res == SZ_OK && inputSize == inProcessed) {
return Data::MakeAdopted(outBuffer, outBufferSize, Data::DeleteProc);
}
delete[] outBuffer;
return nullptr;
}
private:
CLzma2DecMtHandle decoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Decompress(const std::shared_ptr<Data>& data) {
Lzma2Decoder decoder;
return decoder.code(data);
}
} // namespace pag