Writing a compressed buffer to a gzip compatible file - c++

I would like to compress a bunch of data in a buffer and write to a file such that it is gzip compatible. The reason for doing this is that I have multiple threads that can be compressing their own data in parallel and require a lock only when writing to the common output file.
I have some dummy code below based on the zlib.h docs for writing a gz compatible, but I get a gzip: test.gz: unexpected end of file when I try to decompress the output. Can anyone tell me what might be going wrong ?
Thank you
#include <cassert>
#include <fstream>
#include <string.h>
#include <zlib.h>
int main()
{
char compress_in[50] = "I waaaaaaaant tooooooo beeeee compressssssed";
char compress_out[100];
z_stream bufstream;
bufstream.zalloc = Z_NULL;
bufstream.zfree = Z_NULL;
bufstream.opaque = Z_NULL;
bufstream.avail_in = ( uInt )strlen(compress_in) + 1;
bufstream.next_in = ( Bytef * ) compress_in;
bufstream.avail_out = ( uInt )sizeof( compress_out );
bufstream.next_out = ( Bytef * ) compress_out;
int res = deflateInit2( &bufstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY );
assert ( res == Z_OK );
res = deflate( &bufstream, Z_FINISH );
assert( res == Z_STREAM_END );
deflateEnd( &bufstream );
std::ofstream outfile( "test.gz", std::ios::binary | std::ios::out );
outfile.write( compress_out, strlen( compress_out ) + 1 );
outfile.close();
return 0;
}

The length of the compressed data written to the output buffer is the space you provided for the output buffer minus the space remaining in the output buffer. So, sizeof( compress_out ) - bufstream.avail_out. Do:
outfile.write( compress_out, sizeof( compress_out ) - bufstream.avail_out );

Related

Generating a simple CT DICOM image using GDCM

I need to generate a series of CT DICOM images (512x512, MONOCHROME) using the GDCM library. Because of the structure of the application that I am working on, it is ideal for me to separately prepare gdcm::Image and gdcm::File instances for each image and at the end pass them on to gdcmImageWriter using the SetFile() and SetImage() methods.
The gdcmImageWriter::write() fails to write DICOM images. I have already looked at the source code of the VTKGDCMImageWriter class and this GDCM example for hints. It appears that the problem originates from some incompatibilities between gdcm::Image and gdcm::File instances (for instance, both classes contain information about the Photometric Interpretation of a DICOM image) that I pass on to gdcmImageWriter, but I am not sure exactly what those are.
The following simplified C++ code reproduces the error I have been getting:
#include <gdcmFile.h>
#include <gdcmImage.h>
#include <gdcmTag.h>
#include "gdcmDataElement.h"
#include "gdcmByteValue.h"
#include "gdcmPixelFormat.h"
#include "gdcmImageWriter.h"
#include "gdcmAnonymizer.h"
#include <iostream>
#include <string>
InitializeGDCMImage(gdcm::Image* imagePtr);
InitializeGDCMFile( gdcm::File* filePtr );
WriteFile( gdcm::Image* imagePtr , gdcm::File* filePtr , std::string fileName );
int main()
{
std::string fileName = "./TEST.dcm";
// Will be deleted by gdcm::writer.
gdcm::Image* imagePtr = new gdcm::Image;
gdcm::File* filePtr = new gdcm::File;
InitializeGDCMImage(imagePtr);
InitializeGDCMFile( filePtr );
WriteFile( imagePtr , filePtr , fileName );
return 0;
}
where,
void WriteFile( gdcm::Image* imagePtr , gdcm::File* filePtr , std::string fileName )
{
gdcm::ImageWriter* writer = new gdcm::ImageWriter;
writer->SetFileName( fileName.c_str() );
writer->SetImage( *imagePtr );
writer->SetFile( *filePtr );
if( !writer->Write() ){
std::cerr << "ERROR: Could not write to \"" << fileName << "\"" << std::endl;
}
delete writer;
}
WriteFile() sets gdcm::File and gdcm::Image and invokes write().
InitializeGDCMFile() modifies a few DICOM tags using gdcm::Anonymizer, and InitializeGDCMImage() sets the actual pixel values (skipped here for brevity).
void InitializeGDCMFile( gdcm::File* origianlFilePtr )
{
gdcm::File* filePtr = new gdcm::File;
gdcm::Anonymizer anon;
anon.SetFile( *filePtr );
anon.Replace( gdcm::Tag(0x0028,0x0002) , "1" ); //SamplesperPixel
anon.Replace( gdcm::Tag(0x0028,0x0004) , "MONOCHROME2" ); //PhotometricInterpretation
anon.Replace( gdcm::Tag(0x0028,0x0010) , "512" ); //Rows
anon.Replace( gdcm::Tag(0x0028,0x0011) , "512" ); //Columns
anon.Replace( gdcm::Tag(0x0028,0x0030) , "0.781\\0.781" ); //PixelSpacing
anon.Replace( gdcm::Tag(0x0028,0x1050) , "0" ); //WindowCenter
anon.Replace( gdcm::Tag(0x0028,0x1051) , "100" ); //WindowWidth
anon.Replace( gdcm::Tag(0x0028,0x1052) , "0" ); //RescaleIntercept
anon.Replace( gdcm::Tag(0x0028,0x1053) , "1" ); //RescaleSlope
*origianlFilePtr = *filePtr;
}
void InitializeGDCMImage(gdcm::Image* imagePtr)
{
imagePtr->SetPhotometricInterpretation( gdcm::PhotometricInterpretation::MONOCHROME2 );
imagePtr->SetNumberOfDimensions(2);
unsigned int dims[2]={512,512};
imagePtr->SetDimensions( dims );
imagePtr->SetSpacing( 0 , 1. );
imagePtr->SetSpacing( 1 , 1. );
imagePtr->SetIntercept(0.);
imagePtr->SetSlope(1.);
double dirCos[6]={1.,0.,0.,0.,1.,0.};
imagePtr->SetDirectionCosines( dirCos );
char *buffer = new char[512*512*sizeof(int16_t)];
imagePtr->SetPixelFormat( gdcm::PixelFormat::INT16 );
imagePtr->GetDataElement().SetByteValue( buffer , 512*512*sizeof(int16_t) );
imagePtr->GetPixelFormat().SetSamplesPerPixel(1);
delete[] buffer;
}

How to receive a JPEG image over serial port

So I am trying to send a jpeg image (4Kb) from a raspberry pi to my Mac wirelessly using Xbee Series 1. I have an image on the raspberry pi and can read it into binary format. I've used this binary format to save it into another image file and it creates a copy of the image correctly. That tells me that I am reading it correctly. So I am trying to send that data over a serial port (to be transferred by the xbee's) to my Mac. Side note, Xbee's can only transmit I think 80 bytes of data per packet or something. I don't know how that affects what I'm doing though.
My problem is, I do not know how to read the data and properly store it into a jpeg file itself. Most of the Read() functions I have found require you to enter a length to read and I don't know how to tell how long it is since its just a serial stream coming in.
Here is my code to send the jpeg.
#include "xSerial.hpp"
#include <iostream>
#include <cstdlib>
using namespace std;
int copy_file( const char* srcfilename, const char* dstfilename );
int main(){
copy_file("tylerUseThisImage.jpeg", "copyImage.jpeg");
return 0;
}
int copy_file( const char* srcfilename, const char* dstfilename )
{
long len;
char* buf = NULL;
FILE* fp = NULL;
// Open the source file
fp = fopen( srcfilename, "rb" );
if (!fp) return 0;
// Get its length (in bytes)
if (fseek( fp, 0, SEEK_END ) != 0) // This should typically succeed
{ // (beware the 2Gb limitation, though)
fclose( fp );
return 0;
}
len = ftell( fp );
std::cout << len;
rewind( fp );
// Get a buffer big enough to hold it entirely
buf = (char*)malloc( len );
if (!buf)
{
fclose( fp );
return 0;
}
// Read the entire file into the buffer
if (!fread( buf, len, 1, fp ))
{
free( buf );
fclose( fp );
return 0;
}
fclose( fp );
// Open the destination file
fp = fopen( dstfilename, "wb" );
if (!fp)
{
free( buf );
return 0;
}
// this is where I send data in but over serial port.
//serialWrite() is just the standard write() being used
int fd;
fd = xserialOpen("/dev/ttyUSB0", 9600);
serialWrite(fd, buf, len);
//This is where the file gets copied to another file as a test
// Write the entire buffer to file
if (!fwrite( buf, len, 1, fp ))
{
free( buf );
fclose( fp );
return 0;
}
// All done -- return success
fclose( fp );
free( buf );
return 1;
}
On the receive side I know I need to open up the serial port to read and use some sort of read() but I don't know how that is done. Using a serial library it has some functions to check if serial data is available and return the number of characters available to read.
One question about the number of characters available to read, will that number grow as the serial stream comes over or will it immediately tell the entire length of the data to be read?
But finally, I know after I open the serial port, I need read the data into a buffer and then write that buffer to a file but I have not had any luck. This is what I have tried thus far.
// Loop, getting and printing characters
char temp;
bool readComplete = false;
int bytesRead = 0;
fp = fopen("copyImage11.jpeg", "rwb");
for (;;)
{
if(xserialDataAvail(fd) > 0)
{
bytesRead = serialRead(fd, buf, len);
readComplete = true;
}
if (readComplete)
{
if (!fwrite(buf, bytesRead, 1, fp))
{
free(buf);
fclose(fp);
return 0;
}
fclose(fp);
free(buf);
return 1;
}
}
I don't get errors with my code, it just doesnt create the jpeg file correctly. Maybe I'm not transmitting it right, or maybe I'm not reading/writing to file correctly. Any help would be appreciated. Thanks everyone you rock!
If you are defining your own protocol, then you need to have a method for sending the length first.
I would recommend testing your code by sending short blocks of ascii text to confirm your i/o. Once that is working you can use the ascii to set up the transfer; ie send the length, and have your receiver ready for an expected block.

How can I make this code play the wave file for longer?

I couldn't figure out how to create my own sound player, so I have opted to use one from ChiliTomatoNoodle's framework.
The issue I'm having, however, is I have a 180s wave file, that's only playing the first second or so. What do I have to do to make it play longer?
Sound.h:
#pragma once
#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
#include <stdio.h>
class DSound;
class Sound
{
friend DSound;
public:
Sound( const Sound& base );
Sound();
~Sound();
const Sound& operator=( const Sound& rhs );
void Play( int attenuation = DSBVOLUME_MAX );
private:
Sound( IDirectSoundBuffer8* pSecondaryBuffer );
private:
IDirectSoundBuffer8* pBuffer;
};
class DSound
{
private:
struct WaveHeaderType
{
char chunkId[4];
unsigned long chunkSize;
char format[4];
char subChunkId[4];
unsigned long subChunkSize;
unsigned short audioFormat;
unsigned short numChannels;
unsigned long sampleRate;
unsigned long bytesPerSecond;
unsigned short blockAlign;
unsigned short bitsPerSample;
char dataChunkId[4];
unsigned long dataSize;
};
public:
DSound( HWND hWnd );
~DSound();
Sound CreateSound( char* wavFileName );
private:
DSound();
private:
IDirectSound8* pDirectSound;
IDirectSoundBuffer* pPrimaryBuffer;
};
Sound.cpp:
#include "Sound.h"
#include <assert.h>
#pragma comment(lib, "dsound.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib" )
DSound::DSound( HWND hWnd )
: pDirectSound( NULL ),
pPrimaryBuffer( NULL )
{
HRESULT result;
DSBUFFERDESC bufferDesc;
WAVEFORMATEX waveFormat;
result = DirectSoundCreate8( NULL,&pDirectSound,NULL );
assert( !FAILED( result ) );
// Set the cooperative level to priority so the format of the primary sound buffer can be modified.
result = pDirectSound->SetCooperativeLevel( hWnd,DSSCL_PRIORITY );
assert( !FAILED( result ) );
// Setup the primary buffer description.
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
bufferDesc.dwBufferBytes = 0;
bufferDesc.dwReserved = 0;
bufferDesc.lpwfxFormat = NULL;
bufferDesc.guid3DAlgorithm = GUID_NULL;
// Get control of the primary sound buffer on the default sound device.
result = pDirectSound->CreateSoundBuffer( &bufferDesc,&pPrimaryBuffer,NULL );
assert( !FAILED( result ) );
// Setup the format of the primary sound bufffer.
// In this case it is a .WAV file recorded at 44,100 samples per second in 16-bit stereo (cd audio format).
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nSamplesPerSec = 44100;
waveFormat.wBitsPerSample = 16;
waveFormat.nChannels = 2;
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0;
// Set the primary buffer to be the wave format specified.
result = pPrimaryBuffer->SetFormat( &waveFormat );
assert( !FAILED( result ) );
}
DSound::~DSound()
{
if( pPrimaryBuffer )
{
pPrimaryBuffer->Release();
pPrimaryBuffer = NULL;
}
if( pDirectSound )
{
pDirectSound->Release();
pDirectSound = NULL;
}
}
// must be 44.1k 16bit Stereo PCM Wave
Sound DSound::CreateSound( char* wavFileName )
{
int error;
FILE* filePtr;
unsigned int count;
WaveHeaderType waveFileHeader;
WAVEFORMATEX waveFormat;
DSBUFFERDESC bufferDesc;
HRESULT result;
IDirectSoundBuffer* tempBuffer;
IDirectSoundBuffer8* pSecondaryBuffer;
unsigned char* waveData;
unsigned char* bufferPtr;
unsigned long bufferSize;
// Open the wave file in binary.
error = fopen_s( &filePtr,wavFileName,"rb" );
assert( error == 0 );
// Read in the wave file header.
count = fread( &waveFileHeader,sizeof( waveFileHeader ),1,filePtr );
assert( count == 1 );
// Check that the chunk ID is the RIFF format.
assert( (waveFileHeader.chunkId[0] == 'R') &&
(waveFileHeader.chunkId[1] == 'I') &&
(waveFileHeader.chunkId[2] == 'F') &&
(waveFileHeader.chunkId[3] == 'F') );
// Check that the file format is the WAVE format.
assert( (waveFileHeader.format[0] == 'W') &&
(waveFileHeader.format[1] == 'A') &&
(waveFileHeader.format[2] == 'V') &&
(waveFileHeader.format[3] == 'E') );
// Check that the sub chunk ID is the fmt format.
assert( (waveFileHeader.subChunkId[0] == 'f') &&
(waveFileHeader.subChunkId[1] == 'm') &&
(waveFileHeader.subChunkId[2] == 't') &&
(waveFileHeader.subChunkId[3] == ' ') );
// Check that the audio format is WAVE_FORMAT_PCM.
assert( waveFileHeader.audioFormat == WAVE_FORMAT_PCM );
// Check that the wave file was recorded in stereo format.
assert( waveFileHeader.numChannels == 2 );
// Check that the wave file was recorded at a sample rate of 44.1 KHz.
assert( waveFileHeader.sampleRate == 44100 );
// Ensure that the wave file was recorded in 16 bit format.
assert( waveFileHeader.bitsPerSample == 16 );
// Check for the data chunk header.
assert( (waveFileHeader.dataChunkId[0] == 'd') &&
(waveFileHeader.dataChunkId[1] == 'a') &&
(waveFileHeader.dataChunkId[2] == 't') &&
(waveFileHeader.dataChunkId[3] == 'a') );
// Set the wave format of secondary buffer that this wave file will be loaded onto.
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nSamplesPerSec = 44100;
waveFormat.wBitsPerSample = 16;
waveFormat.nChannels = 2;
waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
waveFormat.cbSize = 0;
// Set the buffer description of the secondary sound buffer that the wave file will be loaded onto.
bufferDesc.dwSize = sizeof(DSBUFFERDESC);
bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME;
bufferDesc.dwBufferBytes = waveFileHeader.dataSize;
bufferDesc.dwReserved = 0;
bufferDesc.lpwfxFormat = &waveFormat;
bufferDesc.guid3DAlgorithm = GUID_NULL;
// Create a temporary sound buffer with the specific buffer settings.
result = pDirectSound->CreateSoundBuffer( &bufferDesc,&tempBuffer,NULL );
assert( !FAILED( result ) );
// Test the buffer format against the direct sound 8 interface and create the secondary buffer.
result = tempBuffer->QueryInterface( IID_IDirectSoundBuffer8,(void**)&pSecondaryBuffer );
assert( !FAILED( result ) );
// Release the temporary buffer.
tempBuffer->Release();
tempBuffer = 0;
// Move to the beginning of the wave data which starts at the end of the data chunk header.
fseek( filePtr,sizeof(WaveHeaderType),SEEK_SET );
// Create a temporary buffer to hold the wave file data.
waveData = new unsigned char[ waveFileHeader.dataSize ];
assert( waveData );
// Read in the wave file data into the newly created buffer.
count = fread( waveData,1,waveFileHeader.dataSize,filePtr );
assert( count == waveFileHeader.dataSize);
// Close the file once done reading.
error = fclose( filePtr );
assert( error == 0 );
// Lock the secondary buffer to write wave data into it.
result = pSecondaryBuffer->Lock( 0,waveFileHeader.dataSize,(void**)&bufferPtr,(DWORD*)&bufferSize,NULL,0,0 );
assert( !FAILED( result ) );
// Copy the wave data into the buffer.
memcpy( bufferPtr,waveData,waveFileHeader.dataSize );
// Unlock the secondary buffer after the data has been written to it.
result = pSecondaryBuffer->Unlock( (void*)bufferPtr,bufferSize,NULL,0 );
assert( !FAILED( result ) );
// Release the wave data since it was copied into the secondary buffer.
delete [] waveData;
waveData = NULL;
return Sound( pSecondaryBuffer );
}
Sound::Sound( IDirectSoundBuffer8* pSecondaryBuffer )
: pBuffer( pSecondaryBuffer )
{}
Sound::Sound()
: pBuffer( NULL )
{}
Sound::Sound( const Sound& base )
: pBuffer( base.pBuffer )
{
pBuffer->AddRef();
}
Sound::~Sound()
{
if( pBuffer )
{
pBuffer->Release();
pBuffer = NULL;
}
}
const Sound& Sound::operator=( const Sound& rhs )
{
this->~Sound();
pBuffer = rhs.pBuffer;
pBuffer->AddRef();
return rhs;
}
// attn is the attenuation value in units of 0.01 dB (larger
// negative numbers give a quieter sound, 0 for full volume)
void Sound::Play( int attn )
{
attn = max( attn,DSBVOLUME_MIN );
HRESULT result;
// check that we have a valid buffer
assert( pBuffer != NULL );
// Set position at the beginning of the sound buffer.
result = pBuffer->SetCurrentPosition( 0 );
assert( !FAILED( result ) );
// Set volume of the buffer to attn
result = pBuffer->SetVolume( attn );
assert( !FAILED( result ) );
// Play the contents of the secondary sound buffer.
result = pBuffer->Play( 0,0,0 );
assert( !FAILED( result ) );
}
Thanks for your help in advance!
Assuming you have a .wav file, and you are loading the sound file somewhere along the lines of:
yourSound = audio.CreateSound("fileName.WAV"); //Capslock on WAV
yourSound.Play();
With this comes the declaration of the Sound in the header:
Sound yourSound;
Now because you have probably done this already and this is not working it likely has to do with your file as playing sounds 160 seconds+ should not be a problem.
Are you using a .WAV file for the sound? If so did you happen to convert that (as it is probably a background sound?). If you did try converting it with this converter:
Converter MP3 -> WAV
Please let me know if this works!
Your buffer is probably only large enough to play the first second or so. What you need to do is setup "notifications". See the documentation.
Notifications are a way to ask the audio hardware to let you know when they have reached a specific point in the buffer.
The idea is to setup a notification in the middle of the buffer and at the end of the buffer. When you receive the notification from the notification in the middle, you fill the first half of the buffer with more data. When you receive the notification from the end, you fill the second half of the buffer with more data. This way, you can stream an infinite amount of data with a single buffer.

Simple way to unzip a .zip file using zlib [duplicate]

This question already has answers here:
Unzip a zip file using zlib
(4 answers)
Closed 7 years ago.
Is there a simple example of how to unzip a .zip file and extract the files to a directory? I am currently using zlib, and while I understand that zlib does not directly deal with zip files, there seems to be several additional things in zlibs's "contrib" library. I noticed and read about "minizip", and after reading some documents and looking at some of the code, I do not see a simple example of how to unzip a .zip file and extract the files to a directory.
I would like to find a platform independent way of doing so, but if that is not possible then I need to find a way for windows and mac.
zlib handles the deflate compression/decompression algorithm, but there is more than that in a ZIP file.
You can try libzip. It is free, portable and easy to use.
UPDATE: Here I attach quick'n'dirty example of libzip, with all the error controls ommited:
#include <zip.h>
int main()
{
//Open the ZIP archive
int err = 0;
zip *z = zip_open("foo.zip", 0, &err);
//Search for the file of given name
const char *name = "file.txt";
struct zip_stat st;
zip_stat_init(&st);
zip_stat(z, name, 0, &st);
//Alloc memory for its uncompressed contents
char *contents = new char[st.size];
//Read the compressed file
zip_file *f = zip_fopen(z, name, 0);
zip_fread(f, contents, st.size);
zip_fclose(f);
//And close the archive
zip_close(z);
//Do something with the contents
//delete allocated memory
delete[] contents;
}
Minizip does have an example programs to demonstrate its usage - the files are called minizip.c and miniunz.c.
Update: I had a few minutes so I whipped up this quick, bare bones example for you. It's very smelly C, and I wouldn't use it without major improvements. Hopefully it's enough to get you going for now.
// uzip.c - Simple example of using the minizip API.
// Do not use this code as is! It is educational only, and probably
// riddled with errors and leaks!
#include <stdio.h>
#include <string.h>
#include "unzip.h"
#define dir_delimter '/'
#define MAX_FILENAME 512
#define READ_SIZE 8192
int main( int argc, char **argv )
{
if ( argc < 2 )
{
printf( "usage:\n%s {file to unzip}\n", argv[ 0 ] );
return -1;
}
// Open the zip file
unzFile *zipfile = unzOpen( argv[ 1 ] );
if ( zipfile == NULL )
{
printf( "%s: not found\n" );
return -1;
}
// Get info about the zip file
unz_global_info global_info;
if ( unzGetGlobalInfo( zipfile, &global_info ) != UNZ_OK )
{
printf( "could not read file global info\n" );
unzClose( zipfile );
return -1;
}
// Buffer to hold data read from the zip file.
char read_buffer[ READ_SIZE ];
// Loop to extract all files
uLong i;
for ( i = 0; i < global_info.number_entry; ++i )
{
// Get info about current file.
unz_file_info file_info;
char filename[ MAX_FILENAME ];
if ( unzGetCurrentFileInfo(
zipfile,
&file_info,
filename,
MAX_FILENAME,
NULL, 0, NULL, 0 ) != UNZ_OK )
{
printf( "could not read file info\n" );
unzClose( zipfile );
return -1;
}
// Check if this entry is a directory or file.
const size_t filename_length = strlen( filename );
if ( filename[ filename_length-1 ] == dir_delimter )
{
// Entry is a directory, so create it.
printf( "dir:%s\n", filename );
mkdir( filename );
}
else
{
// Entry is a file, so extract it.
printf( "file:%s\n", filename );
if ( unzOpenCurrentFile( zipfile ) != UNZ_OK )
{
printf( "could not open file\n" );
unzClose( zipfile );
return -1;
}
// Open a file to write out the data.
FILE *out = fopen( filename, "wb" );
if ( out == NULL )
{
printf( "could not open destination file\n" );
unzCloseCurrentFile( zipfile );
unzClose( zipfile );
return -1;
}
int error = UNZ_OK;
do
{
error = unzReadCurrentFile( zipfile, read_buffer, READ_SIZE );
if ( error < 0 )
{
printf( "error %d\n", error );
unzCloseCurrentFile( zipfile );
unzClose( zipfile );
return -1;
}
// Write data to file.
if ( error > 0 )
{
fwrite( read_buffer, error, 1, out ); // You should check return of fwrite...
}
} while ( error > 0 );
fclose( out );
}
unzCloseCurrentFile( zipfile );
// Go the the next entry listed in the zip file.
if ( ( i+1 ) < global_info.number_entry )
{
if ( unzGoToNextFile( zipfile ) != UNZ_OK )
{
printf( "cound not read next file\n" );
unzClose( zipfile );
return -1;
}
}
}
unzClose( zipfile );
return 0;
}
I built and tested it with MinGW/MSYS on Windows like this:
contrib/minizip/$ gcc -I../.. -o unzip uzip.c unzip.c ioapi.c ../../libz.a
contrib/minizip/$ ./unzip.exe /j/zlib-125.zip

Read() from file descriptor hangs

Hey, hopefully this should be my last PTY-related question and I can move onto more exciting issues. (c;
Here's a set of small functions I have written for creating and reading/writing to a pty: http://pastebin.com/m4fcee34d The only problem is that they don't work! After I run the initializer and writeToPty( "ls -l" ) , 'output' from readFromPty is still empty.
Ubuntu, QT C++
EDITED: Ok, I can confirm all this stuff works except for the read loop. In the debuggers' locals/watchers tab it shows that the QString 'output' actually does get the right data put in it, but after it ( the read() ) runs out of characters from the output it runs and then hangs. What is going on and how can I fix it?
Thanks! (c:
#include <iostream>
#include <unistd.h>
#include <utmp.h>
#include <pty.h>
#include <QString>
#include <QThread>
// You also need libutil in your .pro file for this to compile.
class CMkPty
{
public:
CMkPty( int *writeChannel, int *readChannel );
~CMkPty();
int runInPty( char *command );
int writeToPty( char *input );
int readFromPty( QString output );
int m_nPid;
private:
int m_nMaster, m_nSlave, m_nPosition, m_nBytes;
char *m_chName;
void safe_print( char *s );
char m_output;
};
CMkPty::CMkPty( int *masterFD, int *slaveFD )
{
openpty( &m_nMaster, &m_nSlave, (char*)0, __null, __null );
m_nPid = fork();
*masterFD = m_nMaster;
*slaveFD = m_nSlave;
if( m_nPid == 0 )
{
login_tty( m_nSlave );
execl( "/bin/bash", "-l", (char*)0 );
return;
}
else if( m_nPid > 0 )
{
return;
}
else if( m_nPid < 0 )
{
std::cout << "Failed to fork." ;
return;
}
}
CMkPty::~CMkPty()
{
close( m_nMaster );
close( m_nSlave );
}
int CMkPty::writeToPty( char *szInput )
{
int nWriteTest;
write( m_nMaster, szInput, sizeof( szInput ) );
nWriteTest = write( m_nMaster, "\n", 1 );
if( nWriteTest < 0 )
{
std::cout << "Write to PTY failed" ;
return -1;
}
return 0;
}
int CMkPty::readFromPty( QString output )
{
char buffer[ 160 ];
m_nBytes = sizeof( buffer );
while ( ( m_nPosition = read( m_nMaster, buffer, m_nBytes ) ) > 0 )
{
buffer[ m_nPosition ] = 0;
output += buffer;
}
return 0;
}
EDIT: Here's a link to the question with the code that finally worked for me.
I'm note entirely familiar with posix, but after reading this page http://pwet.fr/man/linux/fonctions_bibliotheques/posix/read I had some insight. What's more, I don't see you adjusting your M_nBytes value if you haven't read as much as you were expecting on the first pass of the loop.
edit: from that link, perhaps this will be of some help:
If some process has the pipe open for writing and O_NONBLOCK is clear, read() shall block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
When attempting to read a file (other than a pipe or FIFO) that supports non-blocking reads and has no data currently available:
*
If O_NONBLOCK is clear, read() shall block the calling thread until some data becomes available.
so essentially, if you're not in an error state, and you tell it to keep reading, it will block until it finds something to read.