-rw-r--r-- | core/multimedia/opieplayer/libmpeg3/libmpeg3.c | 2 | ||||
-rw-r--r-- | libopie2/opieui/oimageeffect.cpp | 5 | ||||
-rw-r--r-- | library/global.cpp | 6 | ||||
-rw-r--r-- | noncore/apps/opie-reader/Bkmks.cpp | 1 | ||||
-rw-r--r-- | noncore/apps/opie-sheet/Excel.cpp | 4 | ||||
-rw-r--r-- | noncore/apps/zsafe/zsafe.cpp | 45 | ||||
-rw-r--r-- | noncore/comm/keypebble/vncauth.c | 6 | ||||
-rw-r--r-- | noncore/net/ftplib/ftplib.c | 4 | ||||
-rw-r--r-- | noncore/todayplugins/stockticker/libstocks/csv.c | 106 | ||||
-rw-r--r-- | noncore/todayplugins/stockticker/libstocks/currency.c | 1 | ||||
-rw-r--r-- | noncore/todayplugins/stockticker/libstocks/lists.h | 1 | ||||
-rw-r--r-- | noncore/todayplugins/stockticker/libstocks/stocks.c | 23 | ||||
-rw-r--r-- | rsync/delta.c | 2 |
13 files changed, 152 insertions, 54 deletions
diff --git a/core/multimedia/opieplayer/libmpeg3/libmpeg3.c b/core/multimedia/opieplayer/libmpeg3/libmpeg3.c index acaecf7..c8cd3e2 100644 --- a/core/multimedia/opieplayer/libmpeg3/libmpeg3.c +++ b/core/multimedia/opieplayer/libmpeg3/libmpeg3.c @@ -1,672 +1,672 @@ #include "libmpeg3.h" #include "mpeg3protos.h" #include <stdlib.h> #include <string.h> #define MAX(a, b) ((a) > (b) ? (a) : (b)) mpeg3_t* mpeg3_new(char *path) { int i; mpeg3_t *file = (mpeg3_t*)calloc(1, sizeof(mpeg3_t)); file->cpus = 1; file->fs = mpeg3_new_fs(path); file->have_mmx = mpeg3_mmx_test(); file->demuxer = mpeg3_new_demuxer(file, 0, 0, -1); return file; } int mpeg3_delete(mpeg3_t *file) { int i; for(i = 0; i < file->total_vstreams; i++) mpeg3_delete_vtrack(file, file->vtrack[i]); for(i = 0; i < file->total_astreams; i++) mpeg3_delete_atrack(file, file->atrack[i]); mpeg3_delete_fs(file->fs); mpeg3_delete_demuxer(file->demuxer); free(file); } int mpeg3_check_sig(char *path) { mpeg3_fs_t *fs; unsigned int bits; char *ext; int result = 0; fs = mpeg3_new_fs(path); if(mpeg3io_open_file(fs)) { /* File not found */ - return 0; + return mpeg3_delete_fs(fs); } bits = mpeg3io_read_int32(fs); /* Test header */ if(bits == MPEG3_TOC_PREFIX || bits == MPEG3_TOC_PREFIXLOWER) { result = 1; } else if((((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) || (bits == MPEG3_PACK_START_CODE) || ((bits & 0xfff00000) == 0xfff00000) || (bits == MPEG3_SEQUENCE_START_CODE) || (bits == MPEG3_PICTURE_START_CODE) || (((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE)) { result = 1; ext = strrchr(path, '.'); if(ext) { /* Test file extension. */ if(strncasecmp(ext, ".mp2", 4) && // strncasecmp(ext, ".mp3", 4) && strncasecmp(ext, ".m1v", 4) && strncasecmp(ext, ".m2v", 4) && strncasecmp(ext, ".m2s", 4) && strncasecmp(ext, ".mpg", 4) && strncasecmp(ext, ".vob", 4) && strncasecmp(ext, ".mpeg", 4) && strncasecmp(ext, ".ac3", 4)) result = 0; } } mpeg3io_close_file(fs); mpeg3_delete_fs(fs); return result; } mpeg3_t* mpeg3_open_copy(char *path, mpeg3_t *old_file) { mpeg3_t *file = 0; unsigned int bits; int i, done; /* Initialize the file structure */ file = mpeg3_new(path); /* Need to perform authentication before reading a single byte. */ if(mpeg3io_open_file(file->fs)) { mpeg3_delete(file); return 0; } /* =============================== Create the title objects ========================= */ bits = mpeg3io_read_int32(file->fs); if(bits == MPEG3_TOC_PREFIX || bits == MPEG3_TOC_PREFIXLOWER) /* TOCV */ { /* Table of contents for another file */ if(mpeg3_read_toc(file)) { mpeg3_delete(file); return 0; } mpeg3io_close_file(file->fs); } else if(((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) { /* Transport stream */ file->packet_size = MPEG3_TS_PACKET_SIZE; file->is_transport_stream = 1; } else if(bits == MPEG3_PACK_START_CODE) { /* Program stream */ file->packet_size = MPEG3_DVD_PACKET_SIZE; file->is_program_stream = 1; } else if((bits & 0xfff00000) == 0xfff00000 || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE)) { /* MPEG Audio only */ file->packet_size = MPEG3_DVD_PACKET_SIZE; file->has_audio = 1; file->is_audio_stream = 1; } else if(bits == MPEG3_SEQUENCE_START_CODE || bits == MPEG3_PICTURE_START_CODE) { /* Video only */ file->packet_size = MPEG3_DVD_PACKET_SIZE; file->is_video_stream = 1; } else if(((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) { /* AC3 Audio only */ file->packet_size = MPEG3_DVD_PACKET_SIZE; file->has_audio = 1; file->is_audio_stream = 1; } else { /* file->packet_size = MPEG3_DVD_PACKET_SIZE; */ /* file->is_audio_stream = 1; */ mpeg3_delete(file); fprintf(stderr, "mpeg3_open: not an MPEG 2 stream\n"); return 0; } /* Create title */ /* Copy timecodes from an old demuxer */ if(old_file && mpeg3_get_demuxer(old_file)) { mpeg3demux_copy_titles(file->demuxer, mpeg3_get_demuxer(old_file)); } else /* Start from scratch */ if(!file->demuxer->total_titles) { mpeg3demux_create_title(file->demuxer, 0, 0); } /* =============================== Get title information ========================= */ if(file->is_transport_stream || file->is_program_stream) { /* Create video tracks */ /* Video must be created before audio because audio uses the video timecode */ /* to get its length. */ for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(file->demuxer->vstream_table[i]) { file->vtrack[file->total_vstreams] = mpeg3_new_vtrack(file, i, file->demuxer); if(file->vtrack[file->total_vstreams]) file->total_vstreams++; } } /* Create audio tracks */ for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(file->demuxer->astream_table[i]) { file->atrack[file->total_astreams] = mpeg3_new_atrack(file, i, file->demuxer->astream_table[i], file->demuxer); if(file->atrack[file->total_astreams]) file->total_astreams++; } } } else if(file->is_video_stream) { /* Create video tracks */ file->vtrack[0] = mpeg3_new_vtrack(file, -1, file->demuxer); if(file->vtrack[0]) file->total_vstreams++; } else if(file->is_audio_stream) { /* Create audio tracks */ file->atrack[0] = mpeg3_new_atrack(file, -1, AUDIO_UNKNOWN, file->demuxer); if(file->atrack[0]) file->total_astreams++; } if(file->total_vstreams) file->has_video = 1; if(file->total_astreams) file->has_audio = 1; mpeg3io_close_file(file->fs); return file; } mpeg3_t* mpeg3_open(char *path) { return mpeg3_open_copy(path, 0); } int mpeg3_close(mpeg3_t *file) { /* File is closed in the same procedure it is opened in. */ mpeg3_delete(file); return 0; } int mpeg3_set_cpus(mpeg3_t *file, int cpus) { int i; file->cpus = cpus; for(i = 0; i < file->total_vstreams; i++) mpeg3video_set_cpus(file->vtrack[i]->video, cpus); return 0; } int mpeg3_set_mmx(mpeg3_t *file, int use_mmx) { int i; file->have_mmx = use_mmx; for(i = 0; i < file->total_vstreams; i++) mpeg3video_set_mmx(file->vtrack[i]->video, use_mmx); return 0; } int mpeg3_generate_toc(FILE *output, char *path, int timecode_search, int print_streams) { mpeg3_t *file = mpeg3_open(path); mpeg3_demuxer_t *demuxer; int i; if(file) { fprintf(output, "TOCVERSION 2\n" "PATH: %s\n", path); demuxer = mpeg3_new_demuxer(file, 0, 0, -1); mpeg3demux_create_title(demuxer, timecode_search, output); /* Just print the first title's streams */ if(print_streams) mpeg3demux_print_streams(demuxer, output); fprintf(output, "SIZE: %ld\n", demuxer->titles[demuxer->current_title]->total_bytes); fprintf(output, "PACKETSIZE: %ld\n", demuxer->packet_size); mpeg3demux_print_timecodes(demuxer->titles[demuxer->current_title], output); mpeg3_delete_demuxer(demuxer); mpeg3_close(file); return 0; } return 1; } int mpeg3_read_toc(mpeg3_t *file) { char string[MPEG3_STRLEN]; int number1; /* Test version number */ file->is_program_stream = 1; mpeg3io_seek(file->fs, 0); fscanf(file->fs->fd, "%s %d", string, &number1); if(number1 > 2 || number1 < 2) return 1; /* Read titles */ mpeg3demux_read_titles(file->demuxer); return 0; } int mpeg3_has_audio(mpeg3_t *file) { return file->has_audio; } int mpeg3_total_astreams(mpeg3_t *file) { return file->total_astreams; } int mpeg3_audio_channels(mpeg3_t *file, int stream) { if(file->has_audio) return file->atrack[stream]->channels; return -1; } int mpeg3_sample_rate(mpeg3_t *file, int stream) { if(file->has_audio) return file->atrack[stream]->sample_rate; return -1; } long mpeg3_get_sample(mpeg3_t *file, int stream) { if(file->has_audio) return file->atrack[stream]->current_position; return -1; } int mpeg3_set_sample(mpeg3_t *file, long sample, int stream) { if(file->has_audio) { file->atrack[stream]->current_position = sample; mpeg3audio_seek_sample(file->atrack[stream]->audio, sample); return 0; } return -1; } long mpeg3_audio_samples(mpeg3_t *file, int stream) { if(file->has_audio) return file->atrack[stream]->total_samples; return -1; } int mpeg3_has_video(mpeg3_t *file) { return file->has_video; } int mpeg3_total_vstreams(mpeg3_t *file) { return file->total_vstreams; } int mpeg3_video_width(mpeg3_t *file, int stream) { if(file->has_video) return file->vtrack[stream]->width; return -1; } int mpeg3_video_height(mpeg3_t *file, int stream) { if(file->has_video) return file->vtrack[stream]->height; return -1; } float mpeg3_frame_rate(mpeg3_t *file, int stream) { if(file->has_video) return file->vtrack[stream]->frame_rate; return -1; } long mpeg3_video_frames(mpeg3_t *file, int stream) { if(file->has_video) return file->vtrack[stream]->total_frames; return -1; } long mpeg3_get_frame(mpeg3_t *file, int stream) { if(file->has_video) return file->vtrack[stream]->current_position; return -1; } int mpeg3_set_frame(mpeg3_t *file, long frame, int stream) { if(file->has_video) { file->vtrack[stream]->current_position = frame; mpeg3video_seek_frame(file->vtrack[stream]->video, frame); return 0; } return -1; } int mpeg3_seek_percentage(mpeg3_t *file, double percentage) { int i; for(i = 0; i < file->total_astreams; i++) { mpeg3audio_seek_percentage(file->atrack[i]->audio, percentage); } for(i = 0; i < file->total_vstreams; i++) { mpeg3video_seek_percentage(file->vtrack[i]->video, percentage); } return 0; } int mpeg3_previous_frame(mpeg3_t *file, int stream) { file->last_type_read = 2; file->last_stream_read = stream; if(file->has_video) return mpeg3video_previous_frame(file->vtrack[stream]->video); } double mpeg3_tell_percentage(mpeg3_t *file) { double percent = 0; if(file->last_type_read == 1) { percent = mpeg3demux_tell_percentage(file->atrack[file->last_stream_read]->demuxer); } if(file->last_type_read == 2) { percent = mpeg3demux_tell_percentage(file->vtrack[file->last_stream_read]->demuxer); } return percent; } double mpeg3_get_time(mpeg3_t *file) { double atime = 0, vtime = 0; if(file->is_transport_stream || file->is_program_stream) { /* Timecode only available in transport stream */ if(file->last_type_read == 1) { atime = mpeg3demux_get_time(file->atrack[file->last_stream_read]->demuxer); } else if(file->last_type_read == 2) { vtime = mpeg3demux_get_time(file->vtrack[file->last_stream_read]->demuxer); } } else { /* Use percentage and total time */ if(file->has_audio) { atime = mpeg3demux_tell_percentage(file->atrack[0]->demuxer) * mpeg3_audio_samples(file, 0) / mpeg3_sample_rate(file, 0); } if(file->has_video) { vtime = mpeg3demux_tell_percentage(file->vtrack[0]->demuxer) * mpeg3_video_frames(file, 0) / mpeg3_frame_rate(file, 0); } } return MAX(atime, vtime); } int mpeg3_end_of_audio(mpeg3_t *file, int stream) { int result = 0; result = mpeg3demux_eof(file->atrack[stream]->demuxer); return result; } int mpeg3_end_of_video(mpeg3_t *file, int stream) { int result = 0; result = mpeg3demux_eof(file->vtrack[stream]->demuxer); return result; } int mpeg3_read_frame(mpeg3_t *file, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model, int stream) { int result = -1; if(file->has_video) { result = mpeg3video_read_frame(file->vtrack[stream]->video, file->vtrack[stream]->current_position, output_rows, in_x, in_y, in_w, in_h, out_w, out_h, color_model); file->last_type_read = 2; file->last_stream_read = stream; file->vtrack[stream]->current_position++; } return result; } int mpeg3_drop_frames(mpeg3_t *file, long frames, int stream) { int result = -1; if(file->has_video) { result = mpeg3video_drop_frames(file->vtrack[stream]->video, frames); if(frames > 0) file->vtrack[stream]->current_position += frames; file->last_type_read = 2; file->last_stream_read = stream; } return result; } int mpeg3_read_yuvframe(mpeg3_t *file, char *y_output, char *u_output, char *v_output, int in_x, int in_y, int in_w, int in_h, int stream) { int result = -1; //printf("mpeg3_read_yuvframe 1 %d %d\n", mpeg3demux_tell(file->vtrack[stream]->demuxer), mpeg3demuxer_total_bytes(file->vtrack[stream]->demuxer)); if(file->has_video) { result = mpeg3video_read_yuvframe(file->vtrack[stream]->video, file->vtrack[stream]->current_position, y_output, u_output, v_output, in_x, in_y, in_w, in_h); file->last_type_read = 2; file->last_stream_read = stream; file->vtrack[stream]->current_position++; } //printf("mpeg3_read_yuvframe 2 %d %d\n", mpeg3demux_tell(file->vtrack[stream]->demuxer), mpeg3demuxer_total_bytes(file->vtrack[stream]->demuxer)); return result; } int mpeg3_read_audio(mpeg3_t *file, mpeg3_real_t *output_f, short *output_i, int sampleSpacing, int channel, long samples, int stream) { int result = -1; //printf("mpeg3_read_audio 1 %d %d\n", mpeg3demux_tell(file->atrack[stream]->demuxer), mpeg3demuxer_total_bytes(file->atrack[stream]->demuxer)); if(file->has_audio) { result = mpeg3audio_decode_audio(file->atrack[stream]->audio, output_f, output_i, sampleSpacing, channel, file->atrack[stream]->current_position, samples); file->last_type_read = 1; file->last_stream_read = stream; file->atrack[stream]->current_position += samples; } //printf("mpeg3_read_audio 2 %d %d\n", mpeg3demux_tell(file->atrack[stream]->demuxer), mpeg3demuxer_total_bytes(file->atrack[stream]->demuxer)); return result; } int mpeg3_reread_audio(mpeg3_t *file, mpeg3_real_t *output_f, short *output_i, int sampleSpacing, int channel, long samples, int stream) { if(file->has_audio) { mpeg3_set_sample(file, file->atrack[stream]->current_position - samples, stream); file->last_type_read = 1; file->last_stream_read = stream; return mpeg3_read_audio(file, output_f, output_i, sampleSpacing, channel, samples, stream); } return -1; } int mpeg3_read_audio_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream) { int result = 0; if(file->has_audio) { result = mpeg3audio_read_raw(file->atrack[stream]->audio, output, size, max_size); file->last_type_read = 1; file->last_stream_read = stream; } return result; } int mpeg3_read_video_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream) { int result = 0; if(file->has_video) { result = mpeg3video_read_raw(file->vtrack[stream]->video, output, size, max_size); file->last_type_read = 2; file->last_stream_read = stream; } return result; } diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp index be47eb2..93719bc 100644 --- a/libopie2/opieui/oimageeffect.cpp +++ b/libopie2/opieui/oimageeffect.cpp @@ -1,3773 +1,3776 @@ /* This file is part of the KDE libraries Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org> (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> (C) 2000 Josef Weidendorfer <weidendo@in.tum.de> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // $Id$ #include <math.h> #include <qimage.h> #include <stdlib.h> #include <opie2/oimageeffect.h> #include <opie2/odebug.h> #define MaxRGB 255L #define DegreesToRadians(x) ((x)*M_PI/180.0) using namespace std; using namespace Opie::Core; namespace Opie { namespace Ui { inline unsigned int intensityValue(unsigned int color) { return((unsigned int)((0.299*qRed(color) + 0.587*qGreen(color) + 0.1140000000000001*qBlue(color)))); } //====================================================================== // // Gradient effects // //====================================================================== QImage OImageEffect::gradient(const QSize &size, const QColor &ca, const QColor &cb, GradientType eff, int ncols) { int rDiff, gDiff, bDiff; int rca, gca, bca, rcb, gcb, bcb; QImage image(size, 32); if (size.width() == 0 || size.height() == 0) { odebug << "WARNING: OImageEffect::gradient: invalid image" << oendl; return image; } register int x, y; rDiff = (rcb = cb.red()) - (rca = ca.red()); gDiff = (gcb = cb.green()) - (gca = ca.green()); bDiff = (bcb = cb.blue()) - (bca = ca.blue()); if( eff == VerticalGradient || eff == HorizontalGradient ){ uint *p; uint rgb; register int rl = rca << 16; register int gl = gca << 16; register int bl = bca << 16; if( eff == VerticalGradient ) { int rcdelta = ((1<<16) / size.height()) * rDiff; int gcdelta = ((1<<16) / size.height()) * gDiff; int bcdelta = ((1<<16) / size.height()) * bDiff; for ( y = 0; y < size.height(); y++ ) { p = (uint *) image.scanLine(y); rl += rcdelta; gl += gcdelta; bl += bcdelta; rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) ); for( x = 0; x < size.width(); x++ ) { *p = rgb; p++; } } } else { // must be HorizontalGradient unsigned int *o_src = (unsigned int *)image.scanLine(0); unsigned int *src = o_src; int rcdelta = ((1<<16) / size.width()) * rDiff; int gcdelta = ((1<<16) / size.width()) * gDiff; int bcdelta = ((1<<16) / size.width()) * bDiff; for( x = 0; x < size.width(); x++) { rl += rcdelta; gl += gcdelta; bl += bcdelta; *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16)); } src = o_src; // Believe it or not, manually copying in a for loop is faster // than calling memcpy for each scanline (on the order of ms...). // I think this is due to the function call overhead (mosfet). for (y = 1; y < size.height(); ++y) { p = (unsigned int *)image.scanLine(y); src = o_src; for(x=0; x < size.width(); ++x) *p++ = *src++; } } } else { float rfd, gfd, bfd; float rd = rca, gd = gca, bd = bca; unsigned char *xtable[3]; unsigned char *ytable[3]; unsigned int w = size.width(), h = size.height(); xtable[0] = new unsigned char[w]; xtable[1] = new unsigned char[w]; xtable[2] = new unsigned char[w]; ytable[0] = new unsigned char[h]; ytable[1] = new unsigned char[h]; ytable[2] = new unsigned char[h]; w*=2, h*=2; if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) { // Diagonal dgradient code inspired by BlackBox (mosfet) // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and // Mike Cole <mike@mydot.com>. rfd = (float)rDiff/w; gfd = (float)gDiff/w; bfd = (float)bDiff/w; int dir; for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) { dir = eff == DiagonalGradient? x : size.width() - x - 1; xtable[0][dir] = (unsigned char) rd; xtable[1][dir] = (unsigned char) gd; xtable[2][dir] = (unsigned char) bd; } rfd = (float)rDiff/h; gfd = (float)gDiff/h; bfd = (float)bDiff/h; rd = gd = bd = 0; for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) { ytable[0][y] = (unsigned char) rd; ytable[1][y] = (unsigned char) gd; ytable[2][y] = (unsigned char) bd; } for (y = 0; y < size.height(); y++) { unsigned int *scanline = (unsigned int *)image.scanLine(y); for (x = 0; x < size.width(); x++) { scanline[x] = qRgb(xtable[0][x] + ytable[0][y], xtable[1][x] + ytable[1][y], xtable[2][x] + ytable[2][y]); } } } else if (eff == RectangleGradient || eff == PyramidGradient || eff == PipeCrossGradient || eff == EllipticGradient) { int rSign = rDiff>0? 1: -1; int gSign = gDiff>0? 1: -1; int bSign = bDiff>0? 1: -1; rfd = (float)rDiff / size.width(); gfd = (float)gDiff / size.width(); bfd = (float)bDiff / size.width(); rd = (float)rDiff/2; gd = (float)gDiff/2; bd = (float)bDiff/2; for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd) { xtable[0][x] = (unsigned char) abs((int)rd); xtable[1][x] = (unsigned char) abs((int)gd); xtable[2][x] = (unsigned char) abs((int)bd); } rfd = (float)rDiff/size.height(); gfd = (float)gDiff/size.height(); bfd = (float)bDiff/size.height(); rd = (float)rDiff/2; gd = (float)gDiff/2; bd = (float)bDiff/2; for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd) { ytable[0][y] = (unsigned char) abs((int)rd); ytable[1][y] = (unsigned char) abs((int)gd); ytable[2][y] = (unsigned char) abs((int)bd); } unsigned int rgb; int h = (size.height()+1)>>1; for (y = 0; y < h; y++) { unsigned int *sl1 = (unsigned int *)image.scanLine(y); unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y)); int w = (size.width()+1)>>1; int x2 = size.width()-1; for (x = 0; x < w; x++, x2--) { rgb = 0; if (eff == PyramidGradient) { rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), gcb-gSign*(xtable[1][x]+ytable[1][y]), bcb-bSign*(xtable[2][x]+ytable[2][y])); } if (eff == RectangleGradient) { rgb = qRgb(rcb - rSign * QMAX(xtable[0][x], ytable[0][y]) * 2, gcb - gSign * QMAX(xtable[1][x], ytable[1][y]) * 2, bcb - bSign * QMAX(xtable[2][x], ytable[2][y]) * 2); } if (eff == PipeCrossGradient) { rgb = qRgb(rcb - rSign * QMIN(xtable[0][x], ytable[0][y]) * 2, gcb - gSign * QMIN(xtable[1][x], ytable[1][y]) * 2, bcb - bSign * QMIN(xtable[2][x], ytable[2][y]) * 2); } if (eff == EllipticGradient) { rgb = qRgb(rcb - rSign * (int)sqrt((xtable[0][x]*xtable[0][x] + ytable[0][y]*ytable[0][y])*2.0), gcb - gSign * (int)sqrt((xtable[1][x]*xtable[1][x] + ytable[1][y]*ytable[1][y])*2.0), bcb - bSign * (int)sqrt((xtable[2][x]*xtable[2][x] + ytable[2][y]*ytable[2][y])*2.0)); } sl1[x] = sl2[x] = rgb; sl1[x2] = sl2[x2] = rgb; } } } delete [] xtable[0]; delete [] xtable[1]; delete [] xtable[2]; delete [] ytable[0]; delete [] ytable[1]; delete [] ytable[2]; } // dither if necessary if (ncols && (QPixmap::defaultDepth() < 15 )) { if ( ncols < 2 || ncols > 256 ) ncols = 3; QColor *dPal = new QColor[ncols]; for (int i=0; i<ncols; i++) { dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), gca + gDiff * i / ( ncols - 1 ), bca + bDiff * i / ( ncols - 1 ) ); } dither(image, dPal, ncols); delete [] dPal; } return image; } // ----------------------------------------------------------------------------- //CT this was (before Dirk A. Mueller's speedup changes) // merely the same code as in the above method, but it's supposedly // way less performant since it introduces a lot of supplementary tests // and simple math operations for the calculus of the balance. // (surprizingly, it isn't less performant, in the contrary :-) // Yes, I could have merged them, but then the excellent performance of // the balanced code would suffer with no other gain than a mere // source code and byte code size economy. QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, const QColor &cb, GradientType eff, int xfactor, int yfactor, int ncols) { int dir; // general parameter used for direction switches bool _xanti = false , _yanti = false; if (xfactor < 0) _xanti = true; // negative on X direction if (yfactor < 0) _yanti = true; // negative on Y direction xfactor = abs(xfactor); yfactor = abs(yfactor); if (!xfactor) xfactor = 1; if (!yfactor) yfactor = 1; if (xfactor > 200 ) xfactor = 200; if (yfactor > 200 ) yfactor = 200; // float xbal = xfactor/5000.; // float ybal = yfactor/5000.; float xbal = xfactor/30./size.width(); float ybal = yfactor/30./size.height(); float rat; int rDiff, gDiff, bDiff; int rca, gca, bca, rcb, gcb, bcb; QImage image(size, 32); if (size.width() == 0 || size.height() == 0) { odebug << "WARNING: OImageEffect::unbalancedGradient : invalid image" << oendl; return image; } register int x, y; unsigned int *scanline; rDiff = (rcb = cb.red()) - (rca = ca.red()); gDiff = (gcb = cb.green()) - (gca = ca.green()); bDiff = (bcb = cb.blue()) - (bca = ca.blue()); if( eff == VerticalGradient || eff == HorizontalGradient){ QColor cRow; uint *p; uint rgbRow; if( eff == VerticalGradient) { for ( y = 0; y < size.height(); y++ ) { dir = _yanti ? y : size.height() - 1 - y; p = (uint *) image.scanLine(dir); rat = 1 - exp( - (float)y * ybal ); cRow.setRgb( rcb - (int) ( rDiff * rat ), gcb - (int) ( gDiff * rat ), bcb - (int) ( bDiff * rat ) ); rgbRow = cRow.rgb(); for( x = 0; x < size.width(); x++ ) { *p = rgbRow; p++; } } } else { unsigned int *src = (unsigned int *)image.scanLine(0); for(x = 0; x < size.width(); x++ ) { dir = _xanti ? x : size.width() - 1 - x; rat = 1 - exp( - (float)x * xbal ); src[dir] = qRgb(rcb - (int) ( rDiff * rat ), gcb - (int) ( gDiff * rat ), bcb - (int) ( bDiff * rat )); } // Believe it or not, manually copying in a for loop is faster // than calling memcpy for each scanline (on the order of ms...). // I think this is due to the function call overhead (mosfet). for(y = 1; y < size.height(); ++y) { scanline = (unsigned int *)image.scanLine(y); for(x=0; x < size.width(); ++x) scanline[x] = src[x]; } } } else { int w=size.width(), h=size.height(); unsigned char *xtable[3]; unsigned char *ytable[3]; xtable[0] = new unsigned char[w]; xtable[1] = new unsigned char[w]; xtable[2] = new unsigned char[w]; ytable[0] = new unsigned char[h]; ytable[1] = new unsigned char[h]; ytable[2] = new unsigned char[h]; if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) { for (x = 0; x < w; x++) { dir = _xanti ? x : w - 1 - x; rat = 1 - exp( - (float)x * xbal ); xtable[0][dir] = (unsigned char) ( rDiff/2 * rat ); xtable[1][dir] = (unsigned char) ( gDiff/2 * rat ); xtable[2][dir] = (unsigned char) ( bDiff/2 * rat ); } for (y = 0; y < h; y++) { dir = _yanti ? y : h - 1 - y; rat = 1 - exp( - (float)y * ybal ); ytable[0][dir] = (unsigned char) ( rDiff/2 * rat ); ytable[1][dir] = (unsigned char) ( gDiff/2 * rat ); ytable[2][dir] = (unsigned char) ( bDiff/2 * rat ); } for (y = 0; y < h; y++) { unsigned int *scanline = (unsigned int *)image.scanLine(y); for (x = 0; x < w; x++) { scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]), gcb - (xtable[1][x] + ytable[1][y]), bcb - (xtable[2][x] + ytable[2][y])); } } } else if (eff == RectangleGradient || eff == PyramidGradient || eff == PipeCrossGradient || eff == EllipticGradient) { int rSign = rDiff>0? 1: -1; int gSign = gDiff>0? 1: -1; int bSign = bDiff>0? 1: -1; for (x = 0; x < w; x++) { dir = _xanti ? x : w - 1 - x; rat = 1 - exp( - (float)x * xbal ); xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); } for (y = 0; y < h; y++) { dir = _yanti ? y : h - 1 - y; rat = 1 - exp( - (float)y * ybal ); ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); } for (y = 0; y < h; y++) { unsigned int *scanline = (unsigned int *)image.scanLine(y); for (x = 0; x < w; x++) { if (eff == PyramidGradient) { scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]), gcb-gSign*(xtable[1][x]+ytable[1][y]), bcb-bSign*(xtable[2][x]+ytable[2][y])); } if (eff == RectangleGradient) { scanline[x] = qRgb(rcb - rSign * QMAX(xtable[0][x], ytable[0][y]) * 2, gcb - gSign * QMAX(xtable[1][x], ytable[1][y]) * 2, bcb - bSign * QMAX(xtable[2][x], ytable[2][y]) * 2); } if (eff == PipeCrossGradient) { scanline[x] = qRgb(rcb - rSign * QMIN(xtable[0][x], ytable[0][y]) * 2, gcb - gSign * QMIN(xtable[1][x], ytable[1][y]) * 2, bcb - bSign * QMIN(xtable[2][x], ytable[2][y]) * 2); } if (eff == EllipticGradient) { scanline[x] = qRgb(rcb - rSign * (int)sqrt((xtable[0][x]*xtable[0][x] + ytable[0][y]*ytable[0][y])*2.0), gcb - gSign * (int)sqrt((xtable[1][x]*xtable[1][x] + ytable[1][y]*ytable[1][y])*2.0), bcb - bSign * (int)sqrt((xtable[2][x]*xtable[2][x] + ytable[2][y]*ytable[2][y])*2.0)); } } } } if (ncols && (QPixmap::defaultDepth() < 15 )) { if ( ncols < 2 || ncols > 256 ) ncols = 3; QColor *dPal = new QColor[ncols]; for (int i=0; i<ncols; i++) { dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), gca + gDiff * i / ( ncols - 1 ), bca + bDiff * i / ( ncols - 1 ) ); } dither(image, dPal, ncols); delete [] dPal; } delete [] xtable[0]; delete [] xtable[1]; delete [] xtable[2]; delete [] ytable[0]; delete [] ytable[1]; delete [] ytable[2]; } return image; } //====================================================================== // // Intensity effects // //====================================================================== /* This builds a 256 byte unsigned char lookup table with all * the possible percent values prior to applying the effect, then uses * integer math for the pixels. For any image larger than 9x9 this will be * less expensive than doing a float operation on the 3 color components of * each pixel. (mosfet) */ QImage& OImageEffect::intensity(QImage &image, float percent) { if (image.width() == 0 || image.height() == 0) { odebug << "WARNING: OImageEffect::intensity : invalid image" << oendl; return image; } int segColors = image.depth() > 8 ? 256 : image.numColors(); unsigned char *segTbl = new unsigned char[segColors]; int pixels = image.depth() > 8 ? image.width()*image.height() : image.numColors(); unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : (unsigned int *)image.colorTable(); bool brighten = (percent >= 0); if(percent < 0) percent = -percent; if(brighten){ // keep overflow check out of loops for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp > 255) tmp = 255; segTbl[i] = tmp; } } else{ for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp < 0) tmp = 0; segTbl[i] = tmp; } } if(brighten){ // same here for(int i=0; i < pixels; ++i){ int r = qRed(data[i]); int g = qGreen(data[i]); int b = qBlue(data[i]); int a = qAlpha(data[i]); r = r + segTbl[r] > 255 ? 255 : r + segTbl[r]; g = g + segTbl[g] > 255 ? 255 : g + segTbl[g]; b = b + segTbl[b] > 255 ? 255 : b + segTbl[b]; data[i] = qRgba(r, g, b,a); } } else{ for(int i=0; i < pixels; ++i){ int r = qRed(data[i]); int g = qGreen(data[i]); int b = qBlue(data[i]); int a = qAlpha(data[i]); r = r - segTbl[r] < 0 ? 0 : r - segTbl[r]; g = g - segTbl[g] < 0 ? 0 : g - segTbl[g]; b = b - segTbl[b] < 0 ? 0 : b - segTbl[b]; data[i] = qRgba(r, g, b, a); } } delete [] segTbl; return image; } QImage& OImageEffect::channelIntensity(QImage &image, float percent, RGBComponent channel) { if (image.width() == 0 || image.height() == 0) { odebug << "WARNING: OImageEffect::channelIntensity : invalid image" << oendl; return image; } int segColors = image.depth() > 8 ? 256 : image.numColors(); unsigned char *segTbl = new unsigned char[segColors]; int pixels = image.depth() > 8 ? image.width()*image.height() : image.numColors(); unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : (unsigned int *)image.colorTable(); bool brighten = (percent >= 0); if(percent < 0) percent = -percent; if(brighten){ // keep overflow check out of loops for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp > 255) tmp = 255; segTbl[i] = tmp; } } else{ for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp < 0) tmp = 0; segTbl[i] = tmp; } } if(brighten){ // same here if(channel == Red){ // and here ;-) for(int i=0; i < pixels; ++i){ int c = qRed(data[i]); c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); } } if(channel == Green){ for(int i=0; i < pixels; ++i){ int c = qGreen(data[i]); c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); } } else{ for(int i=0; i < pixels; ++i){ int c = qBlue(data[i]); c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); } } } else{ if(channel == Red){ for(int i=0; i < pixels; ++i){ int c = qRed(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); } } if(channel == Green){ for(int i=0; i < pixels; ++i){ int c = qGreen(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); } } else{ for(int i=0; i < pixels; ++i){ int c = qBlue(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); } } } delete [] segTbl; return image; } // Modulate an image with an RBG channel of another image // QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, ModulationType type, int factor, RGBComponent channel) { if (image.width() == 0 || image.height() == 0 || modImage.width() == 0 || modImage.height() == 0) { odebug << "WARNING: OImageEffect::modulate : invalid image" << oendl; return image; } int r, g, b, h, s, v, a; QColor clr; int mod=0; unsigned int x1, x2, y1, y2; register int x, y; // for image, we handle only depth 32 if (image.depth()<32) image = image.convertDepth(32); // for modImage, we handle depth 8 and 32 if (modImage.depth()<8) modImage = modImage.convertDepth(8); unsigned int *colorTable2 = (modImage.depth()==8) ? modImage.colorTable():0; unsigned int *data1, *data2; unsigned char *data2b; unsigned int color1, color2; x1 = image.width(); y1 = image.height(); x2 = modImage.width(); y2 = modImage.height(); for (y = 0; y < (int)y1; y++) { data1 = (unsigned int *) image.scanLine(y); data2 = (unsigned int *) modImage.scanLine( y%y2 ); data2b = (unsigned char *) modImage.scanLine( y%y2 ); x=0; while(x < (int)x1) { color2 = (colorTable2) ? colorTable2[*data2b] : *data2; if (reverse) { color1 = color2; color2 = *data1; } else color1 = *data1; if (type == Intensity || type == Contrast) { r = qRed(color1); g = qGreen(color1); b = qBlue(color1); if (channel != All) { mod = (channel == Red) ? qRed(color2) : (channel == Green) ? qGreen(color2) : (channel == Blue) ? qBlue(color2) : (channel == Gray) ? qGray(color2) : 0; mod = mod*factor/50; } if (type == Intensity) { if (channel == All) { r += r * factor/50 * qRed(color2)/256; g += g * factor/50 * qGreen(color2)/256; b += b * factor/50 * qBlue(color2)/256; } else { r += r * mod/256; g += g * mod/256; b += b * mod/256; } } else { // Contrast if (channel == All) { r += (r-128) * factor/50 * qRed(color2)/128; g += (g-128) * factor/50 * qGreen(color2)/128; b += (b-128) * factor/50 * qBlue(color2)/128; } else { r += (r-128) * mod/128; g += (g-128) * mod/128; b += (b-128) * mod/128; } } if (r<0) r=0; if (r>255) r=255; if (g<0) g=0; if (g>255) g=255; if (b<0) b=0; if (b>255) b=255; a = qAlpha(*data1); *data1 = qRgba(r, g, b, a); } else if (type == Saturation || type == HueShift) { clr.setRgb(color1); clr.hsv(&h, &s, &v); mod = (channel == Red) ? qRed(color2) : (channel == Green) ? qGreen(color2) : (channel == Blue) ? qBlue(color2) : (channel == Gray) ? qGray(color2) : 0; mod = mod*factor/50; if (type == Saturation) { s -= s * mod/256; if (s<0) s=0; if (s>255) s=255; } else { // HueShift h += mod; while(h<0) h+=360; h %= 360; } clr.setHsv(h, s, v); a = qAlpha(*data1); *data1 = clr.rgb() | ((uint)(a & 0xff) << 24); } data1++; data2++; data2b++; x++; if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; } } } return image; } //====================================================================== // // Blend effects // //====================================================================== // Nice and fast direct pixel manipulation QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity) { if (dst.width() <= 0 || dst.height() <= 0) return dst; if (opacity < 0.0 || opacity > 1.0) { odebug << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1] " << oendl; return dst; } int depth = dst.depth(); if (depth != 32) dst = dst.convertDepth(32); int pixels = dst.width() * dst.height(); int rcol, gcol, bcol; clr.rgb(&rcol, &gcol, &bcol); #ifdef WORDS_BIGENDIAN // ARGB (skip alpha) register unsigned char *data = (unsigned char *)dst.bits() + 1; #else // BGRA register unsigned char *data = (unsigned char *)dst.bits(); #endif for (register int i=0; i<pixels; i++) { #ifdef WORDS_BIGENDIAN *(data++) += (unsigned char)((rcol - *data) * opacity); *(data++) += (unsigned char)((gcol - *data) * opacity); *(data++) += (unsigned char)((bcol - *data) * opacity); #else *(data++) += (unsigned char)((bcol - *data) * opacity); *(data++) += (unsigned char)((gcol - *data) * opacity); *(data++) += (unsigned char)((rcol - *data) * opacity); #endif data++; // skip alpha } return dst; } // Nice and fast direct pixel manipulation QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity) { if (src.width() <= 0 || src.height() <= 0) return dst; if (dst.width() <= 0 || dst.height() <= 0) return dst; if (src.width() != dst.width() || src.height() != dst.height()) { odebug << "WARNING: OImageEffect::blend : src and destination images are not the same size" << oendl; return dst; } if (opacity < 0.0 || opacity > 1.0) { odebug << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]" << oendl; return dst; } if (src.depth() != 32) src = src.convertDepth(32); if (dst.depth() != 32) dst = dst.convertDepth(32); int pixels = src.width() * src.height(); #ifdef WORDS_BIGENDIAN // ARGB (skip alpha) register unsigned char *data1 = (unsigned char *)dst.bits() + 1; register unsigned char *data2 = (unsigned char *)src.bits() + 1; #else // BGRA register unsigned char *data1 = (unsigned char *)dst.bits(); register unsigned char *data2 = (unsigned char *)src.bits(); #endif for (register int i=0; i<pixels; i++) { #ifdef WORDS_BIGENDIAN *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); #else *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); #endif data1++; // skip alpha data2++; } return dst; } QImage& OImageEffect::blend(QImage &image, float initial_intensity, const QColor &bgnd, GradientType eff, bool anti_dir) { if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) { odebug << "WARNING: OImageEffect::blend : invalid image" << oendl; return image; } int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); int r, g, b; int ind; unsigned int xi, xf, yi, yf; unsigned int a; // check the boundaries of the initial intesity param float unaffected = 1; if (initial_intensity > 1) initial_intensity = 1; if (initial_intensity < -1) initial_intensity = -1; if (initial_intensity < 0) { unaffected = 1. + initial_intensity; initial_intensity = 0; } float intensity = initial_intensity; float var = 1. - initial_intensity; if (anti_dir) { initial_intensity = intensity = 1.; var = -var; } register int x, y; unsigned int *data = (unsigned int *)image.bits(); int image_width = image.width(); //Those can't change int image_height = image.height(); if( eff == VerticalGradient || eff == HorizontalGradient ) { // set the image domain to apply the effect to xi = 0, xf = image_width; yi = 0, yf = image_height; if (eff == VerticalGradient) { if (anti_dir) yf = (int)(image_height * unaffected); else yi = (int)(image_height * (1 - unaffected)); } else { if (anti_dir) xf = (int)(image_width * unaffected); else xi = (int)(image_height * (1 - unaffected)); } var /= (eff == VerticalGradient?yf-yi:xf-xi); int ind_base; for (y = yi; y < (int)yf; y++) { intensity = eff == VerticalGradient? intensity + var : initial_intensity; ind_base = image_width * y ; for (x = xi; x < (int)xf ; x++) { if (eff == HorizontalGradient) intensity += var; ind = x + ind_base; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); } } } else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) { float xvar = var / 2 / image_width; // / unaffected; float yvar = var / 2 / image_height; // / unaffected; float tmp; for (x = 0; x < image_width ; x++) { tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1); ind = x; for (y = 0; y < image_height ; y++) { intensity = initial_intensity + tmp + yvar * y; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); ind += image_width; } } } else if (eff == RectangleGradient || eff == EllipticGradient) { float xvar; float yvar; for (x = 0; x < image_width / 2 + image_width % 2; x++) { xvar = var / image_width * (image_width - x*2/unaffected-1); for (y = 0; y < image_height / 2 + image_height % 2; y++) { yvar = var / image_height * (image_height - y*2/unaffected -1); if (eff == RectangleGradient) intensity = initial_intensity + QMAX(xvar, yvar); else intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); if (intensity > 1) intensity = 1; if (intensity < 0) intensity = 0; //NW ind = x + image_width * y ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); //NE ind = image_width - x - 1 + image_width * y ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); } } //CT loop is doubled because of stupid central row/column issue. // other solution? for (x = 0; x < image_width / 2; x++) { xvar = var / image_width * (image_width - x*2/unaffected-1); for (y = 0; y < image_height / 2; y++) { yvar = var / image_height * (image_height - y*2/unaffected -1); if (eff == RectangleGradient) intensity = initial_intensity + QMAX(xvar, yvar); else intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); if (intensity > 1) intensity = 1; if (intensity < 0) intensity = 0; //SW ind = x + image_width * (image_height - y -1) ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); //SE ind = image_width-x-1 + image_width * (image_height - y - 1) ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); } } } else odebug << "OImageEffect::blend effect not implemented" << oendl; return image; } // Not very efficient as we create a third big image... // QImage& OImageEffect::blend(QImage &image1, QImage &image2, GradientType gt, int xf, int yf) { if (image1.width() == 0 || image1.height() == 0 || image2.width() == 0 || image2.height() == 0) return image1; QImage image3; image3 = OImageEffect::unbalancedGradient(image1.size(), QColor(0,0,0), QColor(255,255,255), gt, xf, yf, 0); return blend(image1,image2,image3, Red); // Channel to use is arbitrary } // Blend image2 into image1, using an RBG channel of blendImage // QImage& OImageEffect::blend(QImage &image1, QImage &image2, QImage &blendImage, RGBComponent channel) { if (image1.width() == 0 || image1.height() == 0 || image2.width() == 0 || image2.height() == 0 || blendImage.width() == 0 || blendImage.height() == 0) { odebug << "OImageEffect::blend effect invalid image" << oendl; return image1; } int r, g, b; int ind1, ind2, ind3; unsigned int x1, x2, x3, y1, y2, y3; unsigned int a; register int x, y; // for image1 and image2, we only handle depth 32 if (image1.depth()<32) image1 = image1.convertDepth(32); if (image2.depth()<32) image2 = image2.convertDepth(32); // for blendImage, we handle depth 8 and 32 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8); unsigned int *colorTable3 = (blendImage.depth()==8) ? blendImage.colorTable():0; unsigned int *data1 = (unsigned int *)image1.bits(); unsigned int *data2 = (unsigned int *)image2.bits(); unsigned int *data3 = (unsigned int *)blendImage.bits(); unsigned char *data3b = (unsigned char *)blendImage.bits(); unsigned int color3; x1 = image1.width(); y1 = image1.height(); x2 = image2.width(); y2 = image2.height(); x3 = blendImage.width(); y3 = blendImage.height(); for (y = 0; y < (int)y1; y++) { ind1 = x1*y; ind2 = x2*(y%y2); ind3 = x3*(y%y3); x=0; while(x < (int)x1) { color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3]; a = (channel == Red) ? qRed(color3) : (channel == Green) ? qGreen(color3) : (channel == Blue) ? qBlue(color3) : qGray(color3); r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256; g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256; b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256; a = qAlpha(data1[ind1]); data1[ind1] = qRgba(r, g, b, a); ind1++; ind2++; ind3++; x++; if ( (x%x2) ==0) ind2 -= x2; if ( (x%x3) ==0) ind3 -= x3; } } return image1; } //====================================================================== // // Hash effects // //====================================================================== unsigned int OImageEffect::lHash(unsigned int c) { unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); unsigned char nr, ng, nb; nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr; ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng; nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb; return qRgba(nr, ng, nb, a); } // ----------------------------------------------------------------------------- unsigned int OImageEffect::uHash(unsigned int c) { unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); unsigned char nr, ng, nb; nr = r + (r >> 3); nr = nr < r ? ~0 : nr; ng = g + (g >> 3); ng = ng < g ? ~0 : ng; nb = b + (b >> 3); nb = nb < b ? ~0 : nb; return qRgba(nr, ng, nb, a); } // ----------------------------------------------------------------------------- QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing) { if (image.width() == 0 || image.height() == 0) { odebug << "OImageEffect::hash effect invalid image" << oendl; return image; } register int x, y; unsigned int *data = (unsigned int *)image.bits(); unsigned int ind; //CT no need to do it if not enough space if ((lite == NorthLite || lite == SouthLite)&& (unsigned)image.height() < 2+spacing) return image; if ((lite == EastLite || lite == WestLite)&& (unsigned)image.height() < 2+spacing) return image; if (lite == NorthLite || lite == SouthLite) { for (y = 0 ; y < image.height(); y = y + 2 + spacing) { for (x = 0; x < image.width(); x++) { ind = x + image.width() * y; data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]); ind = ind + image.width(); data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]); } } } else if (lite == EastLite || lite == WestLite) { for (y = 0 ; y < image.height(); y++) { for (x = 0; x < image.width(); x = x + 2 + spacing) { ind = x + image.width() * y; data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]); ind++; data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]); } } } else if (lite == NWLite || lite == SELite) { for (y = 0 ; y < image.height(); y++) { for (x = 0; x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing); x = x + 2 + spacing) { ind = x + image.width() * y + ((y & 1)? 1 : 0); data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]); ind++; data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]); } } } else if (lite == SWLite || lite == NELite) { for (y = 0 ; y < image.height(); y++) { for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) { ind = x + image.width() * y - ((y & 1)? 1 : 0); data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]); ind++; data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]); } } } return image; } //====================================================================== // // Flatten effects // //====================================================================== QImage& OImageEffect::flatten(QImage &img, const QColor &ca, const QColor &cb, int ncols) { if (img.width() == 0 || img.height() == 0) return img; // a bitmap is easy... if (img.depth() == 1) { img.setColor(0, ca.rgb()); img.setColor(1, cb.rgb()); return img; } int r1 = ca.red(); int r2 = cb.red(); int g1 = ca.green(); int g2 = cb.green(); int b1 = ca.blue(); int b2 = cb.blue(); int min = 0, max = 255; QRgb col; // Get minimum and maximum greylevel. if (img.numColors()) { // pseudocolor for (int i = 0; i < img.numColors(); i++) { col = img.color(i); int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; min = QMIN(min, mean); max = QMAX(max, mean); } } else { // truecolor for (int y=0; y < img.height(); y++) for (int x=0; x < img.width(); x++) { col = img.pixel(x, y); int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; min = QMIN(min, mean); max = QMAX(max, mean); } } // Conversion factors float sr = ((float) r2 - r1) / (max - min); float sg = ((float) g2 - g1) / (max - min); float sb = ((float) b2 - b1) / (max - min); // Repaint the image if (img.numColors()) { for (int i=0; i < img.numColors(); i++) { col = img.color(i); int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; int r = (int) (sr * (mean - min) + r1 + 0.5); int g = (int) (sg * (mean - min) + g1 + 0.5); int b = (int) (sb * (mean - min) + b1 + 0.5); img.setColor(i, qRgba(r, g, b, qAlpha(col))); } } else { for (int y=0; y < img.height(); y++) for (int x=0; x < img.width(); x++) { col = img.pixel(x, y); int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; int r = (int) (sr * (mean - min) + r1 + 0.5); int g = (int) (sg * (mean - min) + g1 + 0.5); int b = (int) (sb * (mean - min) + b1 + 0.5); img.setPixel(x, y, qRgba(r, g, b, qAlpha(col))); } } // Dither if necessary if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols))) return img; if (ncols == 1) ncols++; if (ncols > 256) ncols = 256; QColor *pal = new QColor[ncols]; sr = ((float) r2 - r1) / (ncols - 1); sg = ((float) g2 - g1) / (ncols - 1); sb = ((float) b2 - b1) / (ncols - 1); for (int i=0; i<ncols; i++) pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i)); dither(img, pal, ncols); delete[] pal; return img; } //====================================================================== // // Fade effects // //====================================================================== QImage& OImageEffect::fade(QImage &img, float val, const QColor &color) { if (img.width() == 0 || img.height() == 0) return img; // We don't handle bitmaps if (img.depth() == 1) return img; unsigned char tbl[256]; for (int i=0; i<256; i++) tbl[i] = (int) (val * i + 0.5); int red = color.red(); int green = color.green(); int blue = color.blue(); QRgb col; int r, g, b, cr, cg, cb; if (img.depth() <= 8) { // pseudo color for (int i=0; i<img.numColors(); i++) { col = img.color(i); cr = qRed(col); cg = qGreen(col); cb = qBlue(col); if (cr > red) r = cr - tbl[cr - red]; else r = cr + tbl[red - cr]; if (cg > green) g = cg - tbl[cg - green]; else g = cg + tbl[green - cg]; if (cb > blue) b = cb - tbl[cb - blue]; else b = cb + tbl[blue - cb]; img.setColor(i, qRgba(r, g, b, qAlpha(col))); } } else { // truecolor for (int y=0; y<img.height(); y++) { QRgb *data = (QRgb *) img.scanLine(y); for (int x=0; x<img.width(); x++) { col = *data; cr = qRed(col); cg = qGreen(col); cb = qBlue(col); if (cr > red) r = cr - tbl[cr - red]; else r = cr + tbl[red - cr]; if (cg > green) g = cg - tbl[cg - green]; else g = cg + tbl[green - cg]; if (cb > blue) b = cb - tbl[cb - blue]; else b = cb + tbl[blue - cb]; *data++ = qRgba(r, g, b, qAlpha(col)); } } } return img; } //====================================================================== // // Color effects // //====================================================================== // This code is adapted from code (C) Rik Hemsley <rik@kde.org> // // The formula used (r + b + g) /3 is different from the qGray formula // used by Qt. This is because our formula is much much faster. If, // however, it turns out that this is producing sub-optimal images, // then it will have to change (kurt) // // It does produce lower quality grayscale ;-) Use fast == true for the fast // algorithm, false for the higher quality one (mosfet). QImage& OImageEffect::toGray(QImage &img, bool fast) { if (img.width() == 0 || img.height() == 0) return img; if(fast){ if (img.depth() == 32) { register uchar * r(img.bits()); register uchar * g(img.bits() + 1); register uchar * b(img.bits() + 2); uchar * end(img.bits() + img.numBytes()); while (r != end) { *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3 r += 4; g += 4; b += 4; } } else { for (int i = 0; i < img.numColors(); i++) { register uint r = qRed(img.color(i)); register uint g = qGreen(img.color(i)); register uint b = qBlue(img.color(i)); register uint gray = (((r + g) >> 1) + b) >> 1; img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i)))); } } } else{ int pixels = img.depth() > 8 ? img.width()*img.height() : img.numColors(); unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : (unsigned int *)img.colorTable(); int val, i; for(i=0; i < pixels; ++i){ val = qGray(data[i]); data[i] = qRgba(val, val, val, qAlpha(data[i])); } } return img; } // CT 29Jan2000 - desaturation algorithms QImage& OImageEffect::desaturate(QImage &img, float desat) { if (img.width() == 0 || img.height() == 0) return img; if (desat < 0) desat = 0.; if (desat > 1) desat = 1.; int pixels = img.depth() > 8 ? img.width()*img.height() : img.numColors(); unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : (unsigned int *)img.colorTable(); int h, s, v, i; QColor clr; // keep constructor out of loop (mosfet) for(i=0; i < pixels; ++i){ clr.setRgb(data[i]); clr.hsv(&h, &s, &v); clr.setHsv(h, (int)(s * (1. - desat)), v); data[i] = clr.rgb(); } return img; } // Contrast stuff (mosfet) QImage& OImageEffect::contrast(QImage &img, int c) { if (img.width() == 0 || img.height() == 0) return img; if(c > 255) c = 255; if(c < -255) c = -255; int pixels = img.depth() > 8 ? img.width()*img.height() : img.numColors(); unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : (unsigned int *)img.colorTable(); int i, r, g, b; for(i=0; i < pixels; ++i){ r = qRed(data[i]); g = qGreen(data[i]); b = qBlue(data[i]); if(qGray(data[i]) <= 127){ if(r - c <= 255) r -= c; if(g - c <= 255) g -= c; if(b - c <= 255) b -= c; } else{ if(r + c <= 255) r += c; if(g + c <= 255) g += c; if(b + c <= 255) b += c; } data[i] = qRgba(r, g, b, qAlpha(data[i])); } return(img); } //====================================================================== // // Dithering effects // //====================================================================== // adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org) // // Floyd-Steinberg dithering // Ref: Bitmapped Graphics Programming in C++ // Marv Luse, Addison-Wesley Publishing, 1993. QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size) { if (img.width() == 0 || img.height() == 0 || palette == 0 || img.depth() <= 8) return img; QImage dImage( img.width(), img.height(), 8, size ); int i; dImage.setNumColors( size ); for ( i = 0; i < size; i++ ) dImage.setColor( i, palette[ i ].rgb() ); int *rerr1 = new int [ img.width() * 2 ]; int *gerr1 = new int [ img.width() * 2 ]; int *berr1 = new int [ img.width() * 2 ]; memset( rerr1, 0, sizeof( int ) * img.width() * 2 ); memset( gerr1, 0, sizeof( int ) * img.width() * 2 ); memset( berr1, 0, sizeof( int ) * img.width() * 2 ); int *rerr2 = rerr1 + img.width(); int *gerr2 = gerr1 + img.width(); int *berr2 = berr1 + img.width(); for ( int j = 0; j < img.height(); j++ ) { uint *ip = (uint * )img.scanLine( j ); uchar *dp = dImage.scanLine( j ); for ( i = 0; i < img.width(); i++ ) { rerr1[i] = rerr2[i] + qRed( *ip ); rerr2[i] = 0; gerr1[i] = gerr2[i] + qGreen( *ip ); gerr2[i] = 0; berr1[i] = berr2[i] + qBlue( *ip ); berr2[i] = 0; ip++; } *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size ); for ( i = 1; i < img.width()-1; i++ ) { int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); *dp = indx; int rerr = rerr1[i]; rerr -= palette[indx].red(); int gerr = gerr1[i]; gerr -= palette[indx].green(); int berr = berr1[i]; berr -= palette[indx].blue(); // diffuse red error rerr1[ i+1 ] += ( rerr * 7 ) >> 4; rerr2[ i-1 ] += ( rerr * 3 ) >> 4; rerr2[ i ] += ( rerr * 5 ) >> 4; rerr2[ i+1 ] += ( rerr ) >> 4; // diffuse green error gerr1[ i+1 ] += ( gerr * 7 ) >> 4; gerr2[ i-1 ] += ( gerr * 3 ) >> 4; gerr2[ i ] += ( gerr * 5 ) >> 4; gerr2[ i+1 ] += ( gerr ) >> 4; // diffuse red error berr1[ i+1 ] += ( berr * 7 ) >> 4; berr2[ i-1 ] += ( berr * 3 ) >> 4; berr2[ i ] += ( berr * 5 ) >> 4; berr2[ i+1 ] += ( berr ) >> 4; dp++; } *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); } delete [] rerr1; delete [] gerr1; delete [] berr1; img = dImage; return img; } int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size ) { if (palette == 0) return 0; int dr = palette[0].red() - r; int dg = palette[0].green() - g; int db = palette[0].blue() - b; int minDist = dr*dr + dg*dg + db*db; int nearest = 0; for (int i = 1; i < size; i++ ) { dr = palette[i].red() - r; dg = palette[i].green() - g; db = palette[i].blue() - b; int dist = dr*dr + dg*dg + db*db; if ( dist < minDist ) { minDist = dist; nearest = i; } } return nearest; } bool OImageEffect::blend( const QImage & upper, const QImage & lower, QImage & output ) { if ( upper.width() > lower.width() || upper.height() > lower.height() || upper.depth() != 32 || lower.depth() != 32 ) { odebug << "OImageEffect::blend : Sizes not correct" << oendl; return false; } output = lower.copy(); register uchar *i, *o; register int a; register int col; register int w = upper.width(); int row(upper.height() - 1); do { i = upper.scanLine(row); o = output.scanLine(row); col = w << 2; --col; do { while (!(a = i[col]) && (col != 3)) { --col; --col; --col; --col; } --col; o[col] += ((i[col] - o[col]) * a) >> 8; --col; o[col] += ((i[col] - o[col]) * a) >> 8; --col; o[col] += ((i[col] - o[col]) * a) >> 8; } while (col--); } while (row--); return true; } #if 0 // Not yet... bool OImageEffect::blend( const QImage & upper, const QImage & lower, QImage & output, const QRect & destRect ) { output = lower.copy(); return output; } #endif bool OImageEffect::blend( int &x, int &y, const QImage & upper, const QImage & lower, QImage & output ) { int cx=0, cy=0, cw=upper.width(), ch=upper.height(); if ( upper.width() + x > lower.width() || upper.height() + y > lower.height() || x < 0 || y < 0 || upper.depth() != 32 || lower.depth() != 32 ) { if ( x > lower.width() || y > lower.height() ) return false; if ( upper.width()<=0 || upper.height() <= 0 ) return false; if ( lower.width()<=0 || lower.height() <= 0 ) return false; if (x<0) {cx=-x; cw+=x; x=0; }; if (cw + x > lower.width()) { cw=lower.width()-x; }; if (y<0) {cy=-y; ch+=y; y=0; }; if (ch + y > lower.height()) { ch=lower.height()-y; }; if ( cx >= upper.width() || cy >= upper.height() ) return true; if ( cw <= 0 || ch <= 0 ) return true; } output.create(cw,ch,32); // output.setAlphaBuffer(true); // I should do some benchmarks to see if // this is worth the effort register QRgb *i, *o, *b; register int a; register int j,k; for (j=0; j<ch; j++) { b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]); i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]); o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]); k=cw-1; --b; --i; --o; do { while ( !(a=qAlpha(*i)) && k>0 ) { i--; // *o=0; *o=*b; --o; --b; k--; }; // *o=0xFF; *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8), qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8), qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8)); --i; --o; --b; } while (k--); } return true; } bool OImageEffect::blendOnLower( int x, int y, const QImage & upper, const QImage & lower ) { int cx=0, cy=0, cw=upper.width(), ch=upper.height(); if ( upper.depth() != 32 || lower.depth() != 32 ) return false; if ( x + cw > lower.width() || y + ch > lower.height() || x < 0 || y < 0 ) { if ( x > lower.width() || y > lower.height() ) return true; if ( upper.width()<=0 || upper.height() <= 0 ) return true; if ( lower.width()<=0 || lower.height() <= 0 ) return true; if (x<0) {cx=-x; cw+=x; x=0; }; if (cw + x > lower.width()) { cw=lower.width()-x; }; if (y<0) {cy=-y; ch+=y; y=0; }; if (ch + y > lower.height()) { ch=lower.height()-y; }; if ( cx >= upper.width() || cy >= upper.height() ) return true; if ( cw <= 0 || ch <= 0 ) return true; } register uchar *i, *b; register int a; register int k; for (int j=0; j<ch; j++) { b=&lower.scanLine(y+j) [ (x+cw) << 2 ]; i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ]; k=cw-1; --b; --i; do { #ifndef WORDS_BIGENDIAN while ( !(a=*i) && k>0 ) #else while ( !(a=*(i-3)) && k>0 ) #endif { i-=4; b-=4; k--; }; #ifndef WORDS_BIGENDIAN --i; --b; *b += ( ((*i - *b) * a) >> 8 ); --i; --b; *b += ( ((*i - *b) * a) >> 8 ); --i; --b; *b += ( ((*i - *b) * a) >> 8 ); --i; --b; #else *b += ( ((*i - *b) * a) >> 8 ); --i; --b; *b += ( ((*i - *b) * a) >> 8 ); --i; --b; *b += ( ((*i - *b) * a) >> 8 ); i -= 2; b -= 2; #endif } while (k--); } return true; } // For selected icons QImage& OImageEffect::selectedImage( QImage &img, const QColor &col ) { return blend( col, img, 0.5); } // // =================================================================== // Effects originally ported from ImageMagick for PixiePlus, plus a few // new ones. (mosfet 12/29/01) // =================================================================== // void OImageEffect::normalize(QImage &img) { int *histogram, threshold_intensity, intense; int x, y, i; unsigned int gray_value; unsigned int *normalize_map; unsigned int high, low; // allocate histogram and normalize map histogram = (int *)calloc(MaxRGB+1, sizeof(int)); normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int)); if(!normalize_map || !histogram){ owarn << "Unable to allocate normalize histogram and map" << oendl; free(normalize_map); free(histogram); return; } // form histogram if(img.depth() > 8){ // DirectClass unsigned int *data; for(y=0; y < img.height(); ++y){ data = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ gray_value = intensityValue(data[x]); histogram[gray_value]++; } } } else{ // PsudeoClass unsigned char *data; unsigned int *cTable = img.colorTable(); for(y=0; y < img.height(); ++y){ data = (unsigned char *)img.scanLine(y); for(x=0; x < img.width(); ++x){ gray_value = intensityValue(*(cTable+data[x])); histogram[gray_value]++; } } } // find histogram boundaries by locating the 1 percent levels threshold_intensity = (img.width()*img.height())/100; intense = 0; for(low=0; low < MaxRGB; ++low){ intense+=histogram[low]; if(intense > threshold_intensity) break; } intense=0; for(high=MaxRGB; high != 0; --high){ intense+=histogram[high]; if(intense > threshold_intensity) break; } if (low == high){ // Unreasonable contrast; use zero threshold to determine boundaries. threshold_intensity=0; intense=0; for(low=0; low < MaxRGB; ++low){ intense+=histogram[low]; if(intense > threshold_intensity) break; } intense=0; for(high=MaxRGB; high != 0; --high) { intense+=histogram[high]; if(intense > threshold_intensity) break; } - if(low == high) + if(low == high) { + free(histogram); + free(normalize_map); return; // zero span bound } + } // Stretch the histogram to create the normalized image mapping. for(i=0; i <= MaxRGB; i++){ if (i < (int) low) normalize_map[i]=0; else{ if(i > (int) high) normalize_map[i]=MaxRGB; else normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low); } } // Normalize if(img.depth() > 8){ // DirectClass unsigned int *data; for(y=0; y < img.height(); ++y){ data = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ data[x] = qRgba(normalize_map[qRed(data[x])], normalize_map[qGreen(data[x])], normalize_map[qBlue(data[x])], qAlpha(data[x])); } } } else{ // PsudeoClass int colors = img.numColors(); unsigned int *cTable = img.colorTable(); for(i=0; i < colors; ++i){ cTable[i] = qRgba(normalize_map[qRed(cTable[i])], normalize_map[qGreen(cTable[i])], normalize_map[qBlue(cTable[i])], qAlpha(cTable[i])); } } free(histogram); free(normalize_map); } void OImageEffect::equalize(QImage &img) { int *histogram, *map, *equalize_map; int x, y, i, j; unsigned int high, low; // allocate histogram and maps histogram = (int *)calloc(MaxRGB+1, sizeof(int)); map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); if(!histogram || !map || !equalize_map){ owarn << "Unable to allocate equalize histogram and maps" << oendl; free(histogram); free(map); free(equalize_map); return; } // form histogram if(img.depth() > 8){ // DirectClass unsigned int *data; for(y=0; y < img.height(); ++y){ data = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ histogram[intensityValue(data[x])]++; } } } else{ // PsudeoClass unsigned char *data; unsigned int *cTable = img.colorTable(); for(y=0; y < img.height(); ++y){ data = (unsigned char *)img.scanLine(y); for(x=0; x < img.width(); ++x){ histogram[intensityValue(*(cTable+data[x]))]++; } } } // integrate the histogram to get the equalization map. j=0; for(i=0; i <= MaxRGB; i++){ j+=histogram[i]; map[i]=j; } free(histogram); if(map[MaxRGB] == 0){ free(equalize_map); free(map); return; } // equalize low=map[0]; high=map[MaxRGB]; for(i=0; i <= MaxRGB; i++) equalize_map[i]=(unsigned int) ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1)); free(map); // stretch the histogram if(img.depth() > 8){ // DirectClass unsigned int *data; for(y=0; y < img.height(); ++y){ data = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ data[x] = qRgba(equalize_map[qRed(data[x])], equalize_map[qGreen(data[x])], equalize_map[qBlue(data[x])], qAlpha(data[x])); } } } else{ // PsudeoClass int colors = img.numColors(); unsigned int *cTable = img.colorTable(); for(i=0; i < colors; ++i){ cTable[i] = qRgba(equalize_map[qRed(cTable[i])], equalize_map[qGreen(cTable[i])], equalize_map[qBlue(cTable[i])], qAlpha(cTable[i])); } } free(equalize_map); } QImage OImageEffect::sample(QImage &src, int w, int h) { if(w == src.width() && h == src.height()) return(src); double *x_offset, *y_offset; int j, k, y; register int x; QImage dest(w, h, src.depth()); x_offset = (double *)malloc(w*sizeof(double)); y_offset = (double *)malloc(h*sizeof(double)); if(!x_offset || !y_offset){ owarn << "Unable to allocate pixels buffer" << oendl; free(x_offset); free(y_offset); return(src); } // init pixel offsets for(x=0; x < w; ++x) x_offset[x] = x*src.width()/((double)w); for(y=0; y < h; ++y) y_offset[y] = y*src.height()/((double)h); // sample each row if(src.depth() > 8){ // DirectClass source image unsigned int *srcData, *destData; unsigned int *pixels; pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int)); if(!pixels){ owarn << "Unable to allocate pixels buffer" << oendl; free(pixels); free(x_offset); free(y_offset); return(src); } j = (-1); for(y=0; y < h; ++y){ destData = (unsigned int *)dest.scanLine(y); if(j != y_offset[y]){ // read a scan line j = (int)(y_offset[y]); srcData = (unsigned int *)src.scanLine(j); (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int)); } // sample each column for(x=0; x < w; ++x){ k = (int)(x_offset[x]); destData[x] = pixels[k]; } } free(pixels); } else{ // PsudeoClass source image unsigned char *srcData, *destData; unsigned char *pixels; pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char)); if(!pixels){ owarn << "Unable to allocate pixels buffer" << oendl; free(pixels); free(x_offset); free(y_offset); return(src); } // copy colortable dest.setNumColors(src.numColors()); (void)memcpy(dest.colorTable(), src.colorTable(), src.numColors()*sizeof(unsigned int)); // sample image j = (-1); for(y=0; y < h; ++y){ destData = (unsigned char *)dest.scanLine(y); if(j != y_offset[y]){ // read a scan line j = (int)(y_offset[y]); srcData = (unsigned char *)src.scanLine(j); (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char)); } // sample each column for(x=0; x < w; ++x){ k = (int)(x_offset[x]); destData[x] = pixels[k]; } } free(pixels); } free(x_offset); free(y_offset); return(dest); } void OImageEffect::threshold(QImage &img, unsigned int threshold) { int i, count; unsigned int *data; if(img.depth() > 8){ // DirectClass count = img.width()*img.height(); data = (unsigned int *)img.bits(); } else{ // PsudeoClass count = img.numColors(); data = (unsigned int *)img.colorTable(); } for(i=0; i < count; ++i) data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb(); } QImage OImageEffect::charcoal(QImage &src, double factor) { QImage dest(src); dest.detach(); toGray(dest); dest = edge(dest, factor); dest = blur(dest, factor); normalize(dest); dest.invertPixels(false); return(dest); } void OImageEffect::hull(const int x_offset, const int y_offset, const int polarity, const int columns, const int rows, unsigned int *f, unsigned int *g) { int x, y; unsigned int *p, *q, *r, *s; unsigned int v; if(f == NULL || g == NULL) return; p=f+(columns+2); q=g+(columns+2); r=p+(y_offset*(columns+2)+x_offset); for (y=0; y < rows; y++){ p++; q++; r++; if(polarity > 0) for (x=0; x < columns; x++){ v=(*p); if (*r > v) v++; *q=v; p++; q++; r++; } else for(x=0; x < columns; x++){ v=(*p); if (v > (unsigned int) (*r+1)) v--; *q=v; p++; q++; r++; } p++; q++; r++; } p=f+(columns+2); q=g+(columns+2); r=q+(y_offset*(columns+2)+x_offset); s=q-(y_offset*(columns+2)+x_offset); for(y=0; y < rows; y++){ p++; q++; r++; s++; if(polarity > 0) for(x=0; x < (int) columns; x++){ v=(*q); if (((unsigned int) (*s+1) > v) && (*r > v)) v++; *p=v; p++; q++; r++; s++; } else for (x=0; x < columns; x++){ v=(*q); if (((unsigned int) (*s+1) < v) && (*r < v)) v--; *p=v; p++; q++; r++; s++; } p++; q++; r++; s++; } } QImage OImageEffect::despeckle(QImage &src) { int i, j, x, y; unsigned int *blue_channel, *red_channel, *green_channel, *buffer, *alpha_channel; int packets; static const int X[4]= {0, 1, 1,-1}, Y[4]= {1, 0, 1, 1}; unsigned int *destData; QImage dest(src.width(), src.height(), 32); packets = (src.width()+2)*(src.height()+2); red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); buffer = (unsigned int *)calloc(packets, sizeof(unsigned int)); if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel || !buffer){ free(red_channel); free(green_channel); free(blue_channel); free(alpha_channel); free(buffer); return(src); } // copy image pixels to color component buffers j = src.width()+2; if(src.depth() > 8){ // DirectClass source image unsigned int *srcData; for(y=0; y < src.height(); ++y){ srcData = (unsigned int *)src.scanLine(y); ++j; for(x=0; x < src.width(); ++x){ red_channel[j] = qRed(srcData[x]); green_channel[j] = qGreen(srcData[x]); blue_channel[j] = qBlue(srcData[x]); alpha_channel[j] = qAlpha(srcData[x]); ++j; } ++j; } } else{ // PsudeoClass source image unsigned char *srcData; unsigned int *cTable = src.colorTable(); unsigned int pixel; for(y=0; y < src.height(); ++y){ srcData = (unsigned char *)src.scanLine(y); ++j; for(x=0; x < src.width(); ++x){ pixel = *(cTable+srcData[x]); red_channel[j] = qRed(pixel); green_channel[j] = qGreen(pixel); blue_channel[j] = qBlue(pixel); alpha_channel[j] = qAlpha(pixel); ++j; } ++j; } } // reduce speckle in red channel for(i=0; i < 4; i++){ hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer); hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer); hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer); hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer); } // reduce speckle in green channel for (i=0; i < packets; i++) buffer[i]=0; for (i=0; i < 4; i++){ hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer); hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer); hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer); hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer); } // reduce speckle in blue channel for (i=0; i < packets; i++) buffer[i]=0; for (i=0; i < 4; i++){ hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer); hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer); hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer); hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer); } // copy color component buffers to despeckled image j = dest.width()+2; for(y=0; y < dest.height(); ++y) { destData = (unsigned int *)dest.scanLine(y); ++j; for (x=0; x < dest.width(); ++x) { destData[x] = qRgba(red_channel[j], green_channel[j], blue_channel[j], alpha_channel[j]); ++j; } ++j; } free(buffer); free(red_channel); free(green_channel); free(blue_channel); free(alpha_channel); return(dest); } unsigned int OImageEffect::generateNoise(unsigned int pixel, NoiseType noise_type) { #define NoiseEpsilon 1.0e-5 #define NoiseMask 0x7fff #define SigmaUniform 4.0 #define SigmaGaussian 4.0 #define SigmaImpulse 0.10 #define SigmaLaplacian 10.0 #define SigmaMultiplicativeGaussian 0.5 #define SigmaPoisson 0.05 #define TauGaussian 20.0 double alpha, beta, sigma, value; alpha=(double) (rand() & NoiseMask)/NoiseMask; if (alpha == 0.0) alpha=1.0; switch(noise_type){ case UniformNoise: default: { value=(double) pixel+SigmaUniform*(alpha-0.5); break; } case GaussianNoise: { double tau; beta=(double) (rand() & NoiseMask)/NoiseMask; sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta); tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta); value=(double) pixel+ (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau); break; } case MultiplicativeGaussianNoise: { if (alpha <= NoiseEpsilon) sigma=MaxRGB; else sigma=sqrt(-2.0*log(alpha)); beta=(rand() & NoiseMask)/NoiseMask; value=(double) pixel+ pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta); break; } case ImpulseNoise: { if (alpha < (SigmaImpulse/2.0)) value=0; else if (alpha >= (1.0-(SigmaImpulse/2.0))) value=MaxRGB; else value=pixel; break; } case LaplacianNoise: { if (alpha <= 0.5) { if (alpha <= NoiseEpsilon) value=(double) pixel-MaxRGB; else value=(double) pixel+SigmaLaplacian*log(2.0*alpha); break; } beta=1.0-alpha; if (beta <= (0.5*NoiseEpsilon)) value=(double) pixel+MaxRGB; else value=(double) pixel-SigmaLaplacian*log(2.0*beta); break; } case PoissonNoise: { register int i; for (i=0; alpha > exp(-SigmaPoisson*pixel); i++) { beta=(double) (rand() & NoiseMask)/NoiseMask; alpha=alpha*beta; } value=i/SigmaPoisson; break; } } if(value < 0.0) return(0); if(value > MaxRGB) return(MaxRGB); return((unsigned int) (value+0.5)); } QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type) { int x, y; QImage dest(src.width(), src.height(), 32); unsigned int *destData; if(src.depth() > 8){ // DirectClass source image unsigned int *srcData; for(y=0; y < src.height(); ++y){ srcData = (unsigned int *)src.scanLine(y); destData = (unsigned int *)dest.scanLine(y); for(x=0; x < src.width(); ++x){ destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type), generateNoise(qGreen(srcData[x]), noise_type), generateNoise(qBlue(srcData[x]), noise_type), qAlpha(srcData[x])); } } } else{ // PsudeoClass source image unsigned char *srcData; unsigned int *cTable = src.colorTable(); unsigned int pixel; for(y=0; y < src.height(); ++y){ srcData = (unsigned char *)src.scanLine(y); destData = (unsigned int *)dest.scanLine(y); for(x=0; x < src.width(); ++x){ pixel = *(cTable+srcData[x]); destData[x] = qRgba(generateNoise(qRed(pixel), noise_type), generateNoise(qGreen(pixel), noise_type), generateNoise(qBlue(pixel), noise_type), qAlpha(pixel)); } } } return(dest); } unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset, double y_offset, unsigned int background) { double alpha, beta; unsigned int p, q, r, s; int x, y; x = (int)x_offset; y = (int)y_offset; if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height())) return(background); if(image->depth() > 8){ if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { unsigned int *t = (unsigned int *)image->scanLine(y); p = t[x]; q = t[x+1]; r = t[x+image->width()]; s = t[x+image->width()+1]; } else{ unsigned int *t = (unsigned int *)image->scanLine(y); p = background; if((x >= 0) && (y >= 0)){ p = t[x]; } q = background; if(((x+1) < image->width()) && (y >= 0)){ q = t[x+1]; } r = background; if((x >= 0) && ((y+1) < image->height())){ t = (unsigned int *)image->scanLine(y+1); r = t[x+image->width()]; } s = background; if(((x+1) < image->width()) && ((y+1) < image->height())){ t = (unsigned int *)image->scanLine(y+1); s = t[x+image->width()+1]; } } } else{ unsigned int *colorTable = (unsigned int *)image->colorTable(); if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { unsigned char *t; t = (unsigned char *)image->scanLine(y); p = *(colorTable+t[x]); q = *(colorTable+t[x+1]); t = (unsigned char *)image->scanLine(y+1); r = *(colorTable+t[x]); s = *(colorTable+t[x+1]); } else{ unsigned char *t; p = background; if((x >= 0) && (y >= 0)){ t = (unsigned char *)image->scanLine(y); p = *(colorTable+t[x]); } q = background; if(((x+1) < image->width()) && (y >= 0)){ t = (unsigned char *)image->scanLine(y); q = *(colorTable+t[x+1]); } r = background; if((x >= 0) && ((y+1) < image->height())){ t = (unsigned char *)image->scanLine(y+1); r = *(colorTable+t[x]); } s = background; if(((x+1) < image->width()) && ((y+1) < image->height())){ t = (unsigned char *)image->scanLine(y+1); s = *(colorTable+t[x+1]); } } } x_offset -= floor(x_offset); y_offset -= floor(y_offset); alpha = 1.0-x_offset; beta = 1.0-y_offset; return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))), (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))), (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))), (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s))))); } QImage OImageEffect::implode(QImage &src, double factor, unsigned int background) { double amount, distance, radius; double x_center, x_distance, x_scale; double y_center, y_distance, y_scale; unsigned int *destData; int x, y; QImage dest(src.width(), src.height(), 32); // compute scaling factor x_scale = 1.0; y_scale = 1.0; x_center = (double)0.5*src.width(); y_center = (double)0.5*src.height(); radius=x_center; if(src.width() > src.height()) y_scale = (double)src.width()/src.height(); else if(src.width() < src.height()){ x_scale = (double) src.height()/src.width(); radius = y_center; } amount=factor/10.0; if(amount >= 0) amount/=10.0; if(src.depth() > 8){ // DirectClass source image unsigned int *srcData; for(y=0; y < src.height(); ++y){ srcData = (unsigned int *)src.scanLine(y); destData = (unsigned int *)dest.scanLine(y); y_distance=y_scale*(y-y_center); for(x=0; x < src.width(); ++x){ destData[x] = srcData[x]; x_distance = x_scale*(x-x_center); distance= x_distance*x_distance+y_distance*y_distance; if(distance < (radius*radius)){ double factor; // Implode the pixel. factor=1.0; if(distance > 0.0) factor= pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, factor*y_distance/y_scale+y_center, background); } } } } else{ // PsudeoClass source image unsigned char *srcData; unsigned char idx; unsigned int *cTable = src.colorTable(); for(y=0; y < src.height(); ++y){ srcData = (unsigned char *)src.scanLine(y); destData = (unsigned int *)dest.scanLine(y); y_distance=y_scale*(y-y_center); for(x=0; x < src.width(); ++x){ idx = srcData[x]; destData[x] = cTable[idx]; x_distance = x_scale*(x-x_center); distance= x_distance*x_distance+y_distance*y_distance; if(distance < (radius*radius)){ double factor; // Implode the pixel. factor=1.0; if(distance > 0.0) factor= pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, factor*y_distance/y_scale+y_center, background); } } } } return(dest); } QImage OImageEffect::rotate(QImage &img, RotateDirection r) { QImage dest; int x, y; if(img.depth() > 8){ unsigned int *srcData, *destData; switch(r){ case Rotate90: dest.create(img.height(), img.width(), img.depth()); for(y=0; y < img.height(); ++y){ srcData = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ destData = (unsigned int *)dest.scanLine(x); destData[img.height()-y-1] = srcData[x]; } } break; case Rotate180: dest.create(img.width(), img.height(), img.depth()); for(y=0; y < img.height(); ++y){ srcData = (unsigned int *)img.scanLine(y); destData = (unsigned int *)dest.scanLine(img.height()-y-1); for(x=0; x < img.width(); ++x) destData[img.width()-x-1] = srcData[x]; } break; case Rotate270: dest.create(img.height(), img.width(), img.depth()); for(y=0; y < img.height(); ++y){ srcData = (unsigned int *)img.scanLine(y); for(x=0; x < img.width(); ++x){ destData = (unsigned int *)dest.scanLine(img.width()-x-1); destData[y] = srcData[x]; } } break; default: dest = img; break; } } else{ unsigned char *srcData, *destData; unsigned int *srcTable, *destTable; switch(r){ case Rotate90: dest.create(img.height(), img.width(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for(x=0; x < img.numColors(); ++x) destTable[x] = srcTable[x]; for(y=0; y < img.height(); ++y){ srcData = (unsigned char *)img.scanLine(y); for(x=0; x < img.width(); ++x){ destData = (unsigned char *)dest.scanLine(x); destData[img.height()-y-1] = srcData[x]; } } break; case Rotate180: dest.create(img.width(), img.height(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for(x=0; x < img.numColors(); ++x) destTable[x] = srcTable[x]; for(y=0; y < img.height(); ++y){ srcData = (unsigned char *)img.scanLine(y); destData = (unsigned char *)dest.scanLine(img.height()-y-1); for(x=0; x < img.width(); ++x) destData[img.width()-x-1] = srcData[x]; } break; case Rotate270: dest.create(img.height(), img.width(), img.depth()); dest.setNumColors(img.numColors()); srcTable = (unsigned int *)img.colorTable(); destTable = (unsigned int *)dest.colorTable(); for(x=0; x < img.numColors(); ++x) destTable[x] = srcTable[x]; for(y=0; y < img.height(); ++y){ srcData = (unsigned char *)img.scanLine(y); for(x=0; x < img.width(); ++x){ destData = (unsigned char *)dest.scanLine(img.width()-x-1); destData[y] = srcData[x]; } } break; default: dest = img; break; } } return(dest); } void OImageEffect::solarize(QImage &img, double factor) { int i, count; int threshold; unsigned int *data; threshold = (int)(factor*(MaxRGB+1)/100.0); if(img.depth() < 32){ data = (unsigned int *)img.colorTable(); count = img.numColors(); } else{ data = (unsigned int *)img.bits(); count = img.width()*img.height(); } for(i=0; i < count; ++i){ data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]), qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]), qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]), qAlpha(data[i])); } } QImage OImageEffect::spread(QImage &src, unsigned int amount) { int quantum, x, y; int x_distance, y_distance; if(src.width() < 3 || src.height() < 3) return(src); QImage dest(src); dest.detach(); quantum=(amount+1) >> 1; if(src.depth() > 8){ // DirectClass source image unsigned int *p, *q; for(y=0; y < src.height(); y++){ q = (unsigned int *)dest.scanLine(y); for(x=0; x < src.width(); x++){ x_distance = x + ((rand() & (amount+1))-quantum); y_distance = y + ((rand() & (amount+1))-quantum); x_distance = QMIN(x_distance, src.width()-1); y_distance = QMIN(y_distance, src.height()-1); if(x_distance < 0) x_distance = 0; if(y_distance < 0) y_distance = 0; p = (unsigned int *)src.scanLine(y_distance); p += x_distance; *q++=(*p); } } } else{ // PsudeoClass source image // just do colortable values unsigned char *p, *q; for(y=0; y < src.height(); y++){ q = (unsigned char *)dest.scanLine(y); for(x=0; x < src.width(); x++){ x_distance = x + ((rand() & (amount+1))-quantum); y_distance = y + ((rand() & (amount+1))-quantum); x_distance = QMIN(x_distance, src.width()-1); y_distance = QMIN(y_distance, src.height()-1); if(x_distance < 0) x_distance = 0; if(y_distance < 0) y_distance = 0; p = (unsigned char *)src.scanLine(y_distance); p += x_distance; *q++=(*p); } } } return(dest); } QImage OImageEffect::swirl(QImage &src, double degrees, unsigned int background) { double cosine, distance, factor, radius, sine, x_center, x_distance, x_scale, y_center, y_distance, y_scale; int x, y; unsigned int *q; QImage dest(src.width(), src.height(), 32); // compute scaling factor x_center = src.width()/2.0; y_center = src.height()/2.0; radius = QMAX(x_center,y_center); x_scale=1.0; y_scale=1.0; if(src.width() > src.height()) y_scale=(double)src.width()/src.height(); else if(src.width() < src.height()) x_scale=(double)src.height()/src.width(); degrees=DegreesToRadians(degrees); // swirl each row if(src.depth() > 8){ // DirectClass source image unsigned int *p; for(y=0; y < src.height(); y++){ p = (unsigned int *)src.scanLine(y); q = (unsigned int *)dest.scanLine(y); y_distance = y_scale*(y-y_center); for(x=0; x < src.width(); x++){ // determine if the pixel is within an ellipse *q=(*p); x_distance = x_scale*(x-x_center); distance = x_distance*x_distance+y_distance*y_distance; if (distance < (radius*radius)){ // swirl factor = 1.0-sqrt(distance)/radius; sine = sin(degrees*factor*factor); cosine = cos(degrees*factor*factor); *q = interpolateColor(&src, (cosine*x_distance-sine*y_distance)/x_scale+x_center, (sine*x_distance+cosine*y_distance)/y_scale+y_center, background); } p++; q++; } } } else{ // PsudeoClass source image unsigned char *p; unsigned int *cTable = (unsigned int *)src.colorTable(); for(y=0; y < src.height(); y++){ p = (unsigned char *)src.scanLine(y); q = (unsigned int *)dest.scanLine(y); y_distance = y_scale*(y-y_center); for(x=0; x < src.width(); x++){ // determine if the pixel is within an ellipse *q = *(cTable+(*p)); x_distance = x_scale*(x-x_center); distance = x_distance*x_distance+y_distance*y_distance; if (distance < (radius*radius)){ // swirl factor = 1.0-sqrt(distance)/radius; sine = sin(degrees*factor*factor); cosine = cos(degrees*factor*factor); *q = interpolateColor(&src, (cosine*x_distance-sine*y_distance)/x_scale+x_center, (sine*x_distance+cosine*y_distance)/y_scale+y_center, background); } p++; q++; } } } return(dest); } QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength, unsigned int background) { double *sine_map; int x, y; unsigned int *q; QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32); // allocate sine map sine_map = (double *)malloc(dest.width()*sizeof(double)); if(!sine_map) return(src); for(x=0; x < dest.width(); ++x) sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength); // wave image for(y=0; y < dest.height(); ++y){ q = (unsigned int *)dest.scanLine(y); for (x=0; x < dest.width(); x++){ *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background); ++q; } } free(sine_map); return(dest); } QImage OImageEffect::oilPaint(QImage &src, int radius) { // TODO 8bpp src! if(src.depth() < 32){ owarn << "Oil Paint source image < 32bpp. Convert before using!" << oendl; return(src); } int j, k, i, x, y; unsigned int *histogram; unsigned int *s; unsigned int count; unsigned int *srcData, *destData; QImage dest(src); dest.detach(); histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int)); if(!histogram) return(src); // paint each row k=0; for(y = radius; y < src.height(); ++y){ srcData = (unsigned int *)src.scanLine(y-radius); destData = (unsigned int *)dest.scanLine(y); srcData += radius*src.width()+radius; destData += radius; for(x=radius; x < src.width()-radius; ++x){ // determine most frequent color count = 0; for(i=0; i < MaxRGB+1; ++i) histogram[i] = 0; for(i=0; i < radius; ++i){ s = srcData-(radius-1)*src.width()-i-1; for(j =0; j < (2*i+1); ++j){ k = intensityValue(*s); histogram[k]++; if(histogram[k] > count){ *destData = *s; count = histogram[k]; } ++s; } s = srcData+(radius-i)*src.width()-i-1; for(j =0; j < (2*i+1); ++j){ k = intensityValue(*s); histogram[k]++; if(histogram[k] > count){ *destData = *s; count = histogram[k]; } ++s; } } s = srcData-radius; for(j =0; j < (2*i+1); ++j){ k = intensityValue(*s); histogram[k]++; if(histogram[k] > count){ *destData = *s; count = histogram[k]; } ++s; } ++srcData; ++destData; } } free(histogram); return(dest); } // // The following methods work by computing a value from neighboring pixels // (mosfet 12/28/01) // QImage OImageEffect::edge(QImage &src, double factor) { #define Edge(weight) \ total_red+=(weight)*qRed(*s); \ total_green+=(weight)*qGreen(*s); \ total_blue+=(weight)*qBlue(*s); \ total_opacity+=(weight)*qAlpha(*s); \ s++; #define Edge256(weight) \ total_red+=(weight)*qRed(*(cTable+(*s))); \ total_green+=(weight)*qGreen(*(cTable+(*s))); \ total_blue+=(weight)*qBlue(*(cTable+(*s))); \ total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ s++; if(src.width() < 3 || src.height() < 3) return(src); double total_blue, total_green, total_opacity, total_red, weight; int x, y; unsigned int *q; QImage dest(src.width(), src.height(), 32); weight=factor/8.0; if(src.depth() > 8){ // DirectClass source image unsigned int *p, *s; for(y=0; y < src.height(); ++y){ p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); q = (unsigned int *)dest.scanLine(y); // edge detect this row of pixels. *q++=(*(p+src.width())); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Edge(-weight/8); Edge(-weight/8) Edge(-weight/8); s=p+src.width(); Edge(-weight/8); Edge(weight); Edge(-weight/8); s=p+2*src.width(); Edge(-weight/8); Edge(-weight/8); Edge(-weight/8); *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); p++; q++; } p++; *q++=(*p); } } else{ // PsudeoClass source image unsigned char *p, *p2, *p3, *s; unsigned int *cTable = src.colorTable(); int scanLineIdx; for(y=0; y < src.height(); ++y){ scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); p = (unsigned char *)src.scanLine(scanLineIdx); p2 = (unsigned char *)src.scanLine(scanLineIdx+1); p3 = (unsigned char *)src.scanLine(scanLineIdx+2); q = (unsigned int *)dest.scanLine(y); // edge detect this row of pixels. *q++=(*(cTable+(*p2))); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8); s=p2; Edge256(-weight/8); Edge256(weight); Edge256(-weight/8); s=p3; Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8); *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); p++; p2++; p3++; q++; } p++; *q++=(*(cTable+(*p))); } } return(dest); } QImage OImageEffect::sharpen(QImage &src, double factor) { #define Sharpen(weight) \ total_red+=(weight)*qRed(*s); \ total_green+=(weight)*qGreen(*s); \ total_blue+=(weight)*qBlue(*s); \ total_opacity+=(weight)*qAlpha(*s); \ s++; #define Sharpen256(weight) \ total_red+=(weight)*qRed(*(cTable+(*s))); \ total_green+=(weight)*qGreen(*(cTable+(*s))); \ total_blue+=(weight)*qBlue(*(cTable+(*s))); \ total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ s++; if(src.width() < 3 || src.height() < 3) return(src); double total_blue, total_green, total_opacity, total_red; double quantum, weight; unsigned char r, g, b, a; int x, y; unsigned int *q; QImage dest(src.width(), src.height(), 32); weight = ((100.0-factor)/2.0+13.0); quantum = QMAX(weight-12.0, 1.0); if(src.depth() > 8){ // DirectClass source image unsigned int *p, *s; for(y=0; y < src.height(); ++y){ p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); q = (unsigned int *)dest.scanLine(y); // sharpen this row of pixels. *q++=(*(p+src.width())); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Sharpen(-1); Sharpen(-2); Sharpen(-1); s=p+src.width(); Sharpen(-2); Sharpen(weight); Sharpen(-2); s=p+2*src.width(); Sharpen(-1); Sharpen(-2); Sharpen(-1); if(total_red < 0) r=0; else if(total_red > (int)(MaxRGB*quantum)) r = (unsigned char)MaxRGB; else r = (unsigned char)((total_red+(quantum/2.0))/quantum); if(total_green < 0) g = 0; else if(total_green > (int)(MaxRGB*quantum)) g = (unsigned char)MaxRGB; else g = (unsigned char)((total_green+(quantum/2.0))/quantum); if(total_blue < 0) b = 0; else if(total_blue > (int)(MaxRGB*quantum)) b = (unsigned char)MaxRGB; else b = (unsigned char)((total_blue+(quantum/2.0))/quantum); if(total_opacity < 0) a = 0; else if(total_opacity > (int)(MaxRGB*quantum)) a = (unsigned char)MaxRGB; else a= (unsigned char)((total_opacity+(quantum/2.0))/quantum); *q = qRgba(r, g, b, a); p++; q++; } p++; *q++=(*p); } } else{ // PsudeoClass source image unsigned char *p, *p2, *p3, *s; unsigned int *cTable = src.colorTable(); int scanLineIdx; for(y=0; y < src.height(); ++y){ scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); p = (unsigned char *)src.scanLine(scanLineIdx); p2 = (unsigned char *)src.scanLine(scanLineIdx+1); p3 = (unsigned char *)src.scanLine(scanLineIdx+2); q = (unsigned int *)dest.scanLine(y); // sharpen this row of pixels. *q++=(*(cTable+(*p2))); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); s=p2; Sharpen256(-2); Sharpen256(weight); Sharpen256(-2); s=p3; Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); if(total_red < 0) r=0; else if(total_red > (int)(MaxRGB*quantum)) r = (unsigned char)MaxRGB; else r = (unsigned char)((total_red+(quantum/2.0))/quantum); if(total_green < 0) g = 0; else if(total_green > (int)(MaxRGB*quantum)) g = (unsigned char)MaxRGB; else g = (unsigned char)((total_green+(quantum/2.0))/quantum); if(total_blue < 0) b = 0; else if(total_blue > (int)(MaxRGB*quantum)) b = (unsigned char)MaxRGB; else b = (unsigned char)((total_blue+(quantum/2.0))/quantum); if(total_opacity < 0) a = 0; else if(total_opacity > (int)(MaxRGB*quantum)) a = (unsigned char)MaxRGB; else a = (unsigned char)((total_opacity+(quantum/2.0))/quantum); *q = qRgba(r, g, b, a); p++; p2++; p3++; q++; } p++; *q++=(*(cTable+(*p))); } } return(dest); } QImage OImageEffect::emboss(QImage &src) { #define Emboss(weight) \ total_red+=(weight)*qRed(*s); \ total_green+=(weight)*qGreen(*s); \ total_blue+=(weight)*qBlue(*s); \ s++; #define Emboss256(weight) \ total_red+=(weight)*qRed(*(cTable+(*s))); \ total_green+=(weight)*qGreen(*(cTable+(*s))); \ total_blue+=(weight)*qBlue(*(cTable+(*s))); \ s++; if(src.width() < 3 || src.height() < 3) return(src); double total_blue, total_green, total_red; int x, y; unsigned int *q; QImage dest(src.width(), src.height(), 32); if(src.depth() > 8){ // DirectClass source image unsigned int *p, *s; for(y=0; y < src.height(); ++y){ p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); q = (unsigned int *)dest.scanLine(y); // emboss this row of pixels. *q++=(*(p+src.width())); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; s=p; Emboss(-1); Emboss(-2); Emboss( 0); s=p+src.width(); Emboss(-2); Emboss( 0); Emboss( 2); s=p+2*src.width(); Emboss( 0); Emboss( 2); Emboss( 1); total_red += (MaxRGB+1)/2; total_green += (MaxRGB+1)/2; total_blue += (MaxRGB+1)/2; *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 255); p++; q++; } p++; *q++=(*p); } } else{ // PsudeoClass source image unsigned char *p, *p2, *p3, *s; unsigned int *cTable = src.colorTable(); int scanLineIdx; for(y=0; y < src.height(); ++y){ scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); p = (unsigned char *)src.scanLine(scanLineIdx); p2 = (unsigned char *)src.scanLine(scanLineIdx+1); p3 = (unsigned char *)src.scanLine(scanLineIdx+2); q = (unsigned int *)dest.scanLine(y); // emboss this row of pixels. *q++=(*(cTable+(*p2))); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; s=p; Emboss256(-1); Emboss256(-2); Emboss256(0); s=p2; Emboss256(-2); Emboss256(0); Emboss256(2); s=p3; Emboss256(0); Emboss256(2); Emboss256(1); total_red += (MaxRGB+1)/2; total_green += (MaxRGB+1)/2; total_blue += (MaxRGB+1)/2; *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), 255); p++; p2++; p3++; q++; } p++; *q++=(*(cTable+(*p))); } } toGray(dest); normalize(dest); return(dest); } QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth, double elevation) { struct PointInfo{ double x, y, z; }; double distance, normal_distance, shade; int x, y; struct PointInfo light, normal; unsigned int *q; QImage dest(src.width(), src.height(), 32); azimuth = DegreesToRadians(azimuth); elevation = DegreesToRadians(elevation); light.x = MaxRGB*cos(azimuth)*cos(elevation); light.y = MaxRGB*sin(azimuth)*cos(elevation); light.z = MaxRGB*sin(elevation); normal.z= 2*MaxRGB; // constant Z of surface normal if(src.depth() > 8){ // DirectClass source image unsigned int *p, *s0, *s1, *s2; for(y=0; y < src.height(); ++y){ p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); q = (unsigned int *)dest.scanLine(y); // shade this row of pixels. *q++=(*(p+src.width())); p++; s0 = p; s1 = p + src.width(); s2 = p + 2*src.width(); for(x=1; x < src.width()-1; ++x){ // determine the surface normal and compute shading. normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))- (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))- (double) intensityValue(*(s2+1)); normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))- (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)- (double) intensityValue(*(s0+1)); if((normal.x == 0) && (normal.y == 0)) shade=light.z; else{ shade=0.0; distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; if (distance > 0.0){ normal_distance= normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; if(fabs(normal_distance) > 0.0000001) shade=distance/sqrt(normal_distance); } } if(!color_shading){ *q = qRgba((unsigned char)(shade), (unsigned char)(shade), (unsigned char)(shade), qAlpha(*s1)); } else{ *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)), (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)), (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)), qAlpha(*s1)); } ++s0; ++s1; ++s2; q++; } *q++=(*s1); } } else{ // PsudeoClass source image unsigned char *p, *s0, *s1, *s2; int scanLineIdx; unsigned int *cTable = (unsigned int *)src.colorTable(); for(y=0; y < src.height(); ++y){ scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); p = (unsigned char *)src.scanLine(scanLineIdx); q = (unsigned int *)dest.scanLine(y); // shade this row of pixels. s0 = p; s1 = (unsigned char *) src.scanLine(scanLineIdx+1); s2 = (unsigned char *) src.scanLine(scanLineIdx+2); *q++=(*(cTable+(*s1))); ++p; ++s0; ++s1; ++s2; for(x=1; x < src.width()-1; ++x){ // determine the surface normal and compute shading. normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))- (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))- (double) intensityValue(*(cTable+(*(s2+1)))); normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))- (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))- (double) intensityValue(*(cTable+(*(s0+1)))); if((normal.x == 0) && (normal.y == 0)) shade=light.z; else{ shade=0.0; distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; if (distance > 0.0){ normal_distance= normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; if(fabs(normal_distance) > 0.0000001) shade=distance/sqrt(normal_distance); } } if(!color_shading){ *q = qRgba((unsigned char)(shade), (unsigned char)(shade), (unsigned char)(shade), qAlpha(*(cTable+(*s1)))); } else{ *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)), (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)), (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)), qAlpha(*s1)); } ++s0; ++s1; ++s2; q++; } *q++=(*(cTable+(*s1))); } } return(dest); } QImage OImageEffect::blur(QImage &src, double factor) { #define Blur(weight) \ total_red+=(weight)*qRed(*s); \ total_green+=(weight)*qGreen(*s); \ total_blue+=(weight)*qBlue(*s); \ total_opacity+=(weight)*qAlpha(*s); \ s++; #define Blur256(weight) \ total_red+=(weight)*qRed(*(cTable+(*s))); \ total_green+=(weight)*qGreen(*(cTable+(*s))); \ total_blue+=(weight)*qBlue(*(cTable+(*s))); \ total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ s++; if(src.width() < 3 || src.height() < 3) return(src); double quantum, total_blue, total_green, total_opacity, total_red, weight; int x, y; unsigned int *q; QImage dest(src.width(), src.height(), 32); weight=((100.0-factor)/2)+1; quantum = QMAX(weight+12.0, 1.0); if(src.depth() > 8){ // DirectClass source image unsigned int *p, *s; for(y=0; y < src.height(); ++y){ p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); q = (unsigned int *)dest.scanLine(y); // blur this row of pixels. *q++=(*(p+src.width())); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Blur(1); Blur(2); Blur(1); s=p+src.width(); Blur(2); Blur(weight); Blur(2); s=p+2*src.width(); Blur(1); Blur(2); Blur(1); *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), (unsigned char)((total_green+(quantum/2))/quantum), (unsigned char)((total_blue+(quantum/2))/quantum), (unsigned char)((total_opacity+(quantum/2))/quantum)); p++; q++; } p++; *q++=(*p); } } else{ // PsudeoClass source image unsigned char *p, *p2, *p3, *s; unsigned int *cTable = src.colorTable(); int scanLineIdx; for(y=0; y < src.height(); ++y){ scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); p = (unsigned char *)src.scanLine(scanLineIdx); p2 = (unsigned char *)src.scanLine(scanLineIdx+1); p3 = (unsigned char *)src.scanLine(scanLineIdx+2); q = (unsigned int *)dest.scanLine(y); // blur this row of pixels. *q++=(*(cTable+(*p2))); for(x=1; x < src.width()-1; ++x){ // compute weighted average of target pixel color components. total_red=0.0; total_green=0.0; total_blue=0.0; total_opacity=0.0; s=p; Blur256(1); Blur256(2); Blur256(1); s=p2; Blur256(2); Blur256(weight); Blur256(2); s=p3; Blur256(1); Blur256(2); Blur256(1); *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), (unsigned char)((total_green+(quantum/2))/quantum), (unsigned char)((total_blue+(quantum/2))/quantum), (unsigned char)((total_opacity+(quantum/2))/quantum)); p++; p2++; p3++; q++; } p++; *q++=(*(cTable+(*p))); } } return(dest); } // High quality, expensive HSV contrast. You can do a faster one by just // taking a grayscale threshold (ie: 128) and incrementing RGB color // channels above it and decrementing those below it, but this gives much // better results. (mosfet 12/28/01) void OImageEffect::contrastHSV(QImage &img, bool sharpen) { int i, sign; unsigned int *data; int count; double brightness, scale, theta; QColor c; int h, s, v; sign = sharpen ? 1 : -1; scale=0.5000000000000001; if(img.depth() > 8){ count = img.width()*img.height(); data = (unsigned int *)img.bits(); } else{ count = img.numColors(); data = (unsigned int *)img.colorTable(); } for(i=0; i < count; ++i){ c.setRgb(data[i]); c.hsv(&h, &s, &v); brightness = v/255.0; theta=(brightness-0.5)*M_PI; brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign); if (brightness > 1.0) brightness=1.0; else if (brightness < 0) brightness=0.0; v = (int)(brightness*255); c.setHsv(h, s, v); data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i])); } } } } diff --git a/library/global.cpp b/library/global.cpp index 7bdd0b1..1895006 100644 --- a/library/global.cpp +++ b/library/global.cpp @@ -1,860 +1,864 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #define QTOPIA_INTERNAL_LANGLIST #include <qpe/qpedebug.h> #include <qpe/global.h> #include <qpe/qdawg.h> #include <qpe/qpeapplication.h> #include <qpe/resource.h> #include <qpe/storage.h> #include <qpe/applnk.h> #include <qpe/qcopenvelope_qws.h> #include <qpe/config.h> #include <qlabel.h> #include <qtimer.h> #include <qmap.h> #include <qdict.h> #include <qdir.h> #include <qmessagebox.h> #include <qregexp.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <qwindowsystem_qws.h> // for qwsServer #include <qdatetime.h> //#include "quickexec_p.h" class Emitter : public QObject { Q_OBJECT public: Emitter( QWidget* receiver, const QString& document ) { connect(this, SIGNAL(setDocument(const QString&)), receiver, SLOT(setDocument(const QString&))); emit setDocument(document); disconnect(this, SIGNAL(setDocument(const QString&)), receiver, SLOT(setDocument(const QString&))); } signals: void setDocument(const QString&); }; class StartingAppList : public QObject { Q_OBJECT public: static void add( const QString& name ); static bool isStarting( const QString name ); private slots: void handleNewChannel( const QString &); private: StartingAppList( QObject *parent=0, const char* name=0 ) ; QDict<QTime> dict; static StartingAppList *appl; }; StartingAppList* StartingAppList::appl = 0; StartingAppList::StartingAppList( QObject *parent, const char* name ) :QObject( parent, name ) { #if QT_VERSION >= 232 && defined(QWS) connect( qwsServer, SIGNAL( newChannel(const QString&)), this, SLOT( handleNewChannel(const QString&)) ); #endif dict.setAutoDelete( TRUE ); } void StartingAppList::add( const QString& name ) { #if QT_VERSION >= 232 && !defined(QT_NO_COP) if ( !appl ) appl = new StartingAppList; QTime *t = new QTime; t->start(); appl->dict.insert( "QPE/Application/" + name, t ); #endif } bool StartingAppList::isStarting( const QString name ) { #if QT_VERSION >= 232 && !defined(QT_NO_COP) if ( appl ) { QTime *t = appl->dict.find( "QPE/Application/" + name ); if ( !t ) return FALSE; if ( t->elapsed() > 10000 ) { // timeout in case of crash or something appl->dict.remove( "QPE/Application/" + name ); return FALSE; } return TRUE; } #endif return FALSE; } void StartingAppList::handleNewChannel( const QString & name ) { #if QT_VERSION >= 232 && !defined(QT_NO_COP) dict.remove( name ); #endif } static bool docDirCreated = FALSE; static QDawg* fixed_dawg = 0; static QDict<QDawg> *named_dawg = 0; static QString qpeDir() { QString dir = getenv("OPIEDIR"); if ( dir.isEmpty() ) dir = ".."; return dir; } static QString dictDir() { return qpeDir() + "/etc/dict"; } /*! \class Global global.h \brief The Global class provides application-wide global functions. The Global functions are grouped as follows: \tableofcontents \section1 User Interface The statusMessage() function provides short-duration messages to the user. The showInputMethod() function shows the current input method, and hideInputMethod() hides the input method. \section1 Document related The findDocuments() function creates a set of \link doclnk.html DocLnk\endlink objects in a particular folder. \section1 Filesystem related Global provides an applicationFileName() function that returns the full path of an application-specific file. The execute() function runs an application. \section1 Word list related A list of words relevant to the current locale is maintained by the system. The list is held in a \link qdawg.html DAWG\endlink (implemented by the QDawg class). This list is used, for example, by the pickboard input method. The global QDawg is returned by fixedDawg(); this cannot be updated. An updatable copy of the global QDawg is returned by addedDawg(). Applications may have their own word lists stored in \l{QDawg}s which are returned by dawg(). Use addWords() to add words to the updateable copy of the global QDawg or to named application \l{QDawg}s. \section1 Quoting The shellQuote() function quotes a string suitable for passing to a shell. The stringQuote() function backslash escapes '\' and '"' characters. \section1 Hardware The implementation of the writeHWClock() function depends on the AlarmServer implementation. If the AlarmServer is using atd the clock will be synced to hardware. If opie-alarm is used the hardware clock will be synced before suspending the device. opie-alarm is used by iPAQ and Zaurii implementation \ingroup qtopiaemb */ /*! \internal */ Global::Global() { } /*! Returns the unchangeable QDawg that contains general words for the current locale. \sa addedDawg() */ const QDawg& Global::fixedDawg() { if ( !fixed_dawg ) { if ( !docDirCreated ) createDocDir(); fixed_dawg = new QDawg; QString dawgfilename = dictDir() + "/dawg"; QString words_lang; QStringList langs = Global::languageList(); for (QStringList::ConstIterator it = langs.begin(); it!=langs.end(); ++it) { QString lang = *it; words_lang = dictDir() + "/words." + lang; QString dawgfilename_lang = dawgfilename + "." + lang; if ( QFile::exists(dawgfilename_lang) || QFile::exists(words_lang) ) { dawgfilename = dawgfilename_lang; break; } } QFile dawgfile(dawgfilename); if ( !dawgfile.exists() ) { QString fn = dictDir() + "/words"; if ( QFile::exists(words_lang) ) fn = words_lang; QFile in(fn); if ( in.open(IO_ReadOnly) ) { fixed_dawg->createFromWords(&in); if (dawgfile.open(IO_WriteOnly)) fixed_dawg->write(&dawgfile); dawgfile.close(); } } else fixed_dawg->readFile(dawgfilename); } return *fixed_dawg; } /*! Returns the changeable QDawg that contains general words for the current locale. \sa fixedDawg() */ const QDawg& Global::addedDawg() { return dawg("local"); } /*! Returns the QDawg with the given \a name. This is an application-specific word list. \a name should not contain "/". */ const QDawg& Global::dawg(const QString& name) { createDocDir(); if ( !named_dawg ) named_dawg = new QDict<QDawg>; QDawg* r = named_dawg->find(name); if ( !r ) { r = new QDawg; named_dawg->insert(name,r); QString dawgfilename = applicationFileName("Dictionary", name ) + ".dawg"; QFile dawgfile(dawgfilename); if ( dawgfile.open(IO_ReadOnly) ) r->readFile(dawgfilename); } return *r; } /*! \overload Adds \a wordlist to the addedDawg(). Note that the addition of words persists between program executions (they are saved in the dictionary files), so you should confirm the words with the user before adding them. */ void Global::addWords(const QStringList& wordlist) { addWords("local",wordlist); } /*! \overload Adds \a wordlist to the addedDawg(). Note that the addition of words persists between program executions (they are saved in the dictionary files), so you should confirm the words with the user before adding them. */ void Global::addWords(const QString& dictname, const QStringList& wordlist) { QDawg& d = (QDawg&)dawg(dictname); QStringList all = d.allWords() + wordlist; d.createFromWords(all); QString dawgfilename = applicationFileName("Dictionary", dictname) + ".dawg"; QFile dawgfile(dawgfilename); if ( dawgfile.open(IO_WriteOnly) ) { d.write(&dawgfile); dawgfile.close(); } // #### Re-read the dawg here if we use mmap(). // #### Signal other processes to re-read. } /*! Returns the full path for the application called \a appname, with the given \a filename. Returns QString::null if there was a problem creating the directory tree for \a appname. If \a filename contains "/", it is the caller's responsibility to ensure that those directories exist. */ QString Global::applicationFileName(const QString& appname, const QString& filename) { QDir d; QString r = getenv("HOME"); r += "/Applications/"; if ( !QFile::exists( r ) ) if ( d.mkdir(r) == false ) return QString::null; r += appname; if ( !QFile::exists( r ) ) if ( d.mkdir(r) == false ) return QString::null; r += "/"; r += filename; return r; } /*! \internal */ void Global::createDocDir() { if ( !docDirCreated ) { docDirCreated = TRUE; mkdir( QPEApplication::documentDir().latin1(), 0755 ); } } /*! Displays a status \a message to the user. This usually appears in the taskbar for a short amount of time, then disappears. */ void Global::statusMessage(const QString& message) { #if !defined(QT_NO_COP) QCopEnvelope e( "QPE/TaskBar", "message(QString)" ); e << message; #endif } /*! \internal */ void Global::applyStyle() { #if !defined(QT_NO_COP) QCopChannel::send( "QPE/System", "applyStyle()" ); #else ((QPEApplication *)qApp)->applyStyle(); // apply without needing QCop for floppy version #endif } /*! \internal */ QWidget *Global::shutdown( bool ) { #if !defined(QT_NO_COP) QCopChannel::send( "QPE/System", "shutdown()" ); #endif return 0; } /*! \internal */ QWidget *Global::restart( bool ) { #if !defined(QT_NO_COP) QCopChannel::send( "QPE/System", "restart()" ); #endif return 0; } /*! Explicitly show the current input method. Input methods are indicated in the taskbar by a small icon. If the input method is activated (shown) then it takes up some proportion of the bottom of the screen, to allow the user to interact (input characters) with it. \sa hideInputMethod() */ void Global::showInputMethod() { #if !defined(QT_NO_COP) QCopChannel::send( "QPE/TaskBar", "showInputMethod()" ); #endif } /*! Explicitly hide the current input method. The current input method is still indicated in the taskbar, but no longer takes up screen space, and can no longer be interacted with. \sa showInputMethod() */ void Global::hideInputMethod() { #if !defined(QT_NO_COP) QCopChannel::send( "QPE/TaskBar", "hideInputMethod()" ); #endif } /*! \internal */ bool Global::isBuiltinCommand( const QString &name ) { if(!builtin) return FALSE; // yes, it can happen for (int i = 0; builtin[i].file; i++) { if ( builtin[i].file == name ) { return TRUE; } } return FALSE; } Global::Command* Global::builtin=0; QGuardedPtr<QWidget> *Global::running=0; /*! \class Global::Command \brief The Global::Command class is internal. \internal */ /*! \internal */ void Global::setBuiltinCommands( Command* list ) { if ( running ) delete [] running; builtin = list; int count = 0; if (!builtin) return; while ( builtin[count].file ) count++; running = new QGuardedPtr<QWidget> [ count ]; } /*! \internal */ void Global::setDocument( QWidget* receiver, const QString& document ) { Emitter emitter(receiver,document); } /*! \internal */ bool Global::terminateBuiltin( const QString& n ) { if (!builtin) return FALSE; for (int i = 0; builtin[i].file; i++) { if ( builtin[i].file == n ) { delete running[i]; return TRUE; } } return FALSE; } /*! \internal */ void Global::terminate( const AppLnk* app ) { //if ( terminateBuiltin(app->exec()) ) return; // maybe? haven't tried this #ifndef QT_NO_COP QCString channel = "QPE/Application/" + app->exec().utf8(); if ( QCopChannel::isRegistered(channel) ) { QCopEnvelope e(channel, "quit()"); } #endif } /*! Low-level function to run command \a c. \warning Do not use this function. Use execute instead. \sa execute() */ void Global::invoke(const QString &c) { // Convert the command line in to a list of arguments QStringList list = QStringList::split(QRegExp(" *"),c); #if !defined(QT_NO_COP) QString ap=list[0]; // see if the application is already running // XXX should lock file /tmp/qcop-msg-ap if ( QCopChannel::isRegistered( ("QPE/Application/" + ap).latin1() ) ) { // If the channel is already register, the app is already running, so show it. - { QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); } + { + QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); + } //QCopEnvelope e("QPE/System", "notBusy(QString)" ); //e << ap; return; } // XXX should unlock file /tmp/qcop-msg-ap //see if it is being started if ( StartingAppList::isStarting( ap ) ) { // FIXME take it out for now, since it leads to a much to short showing of wait if // some entry is clicked. // Real cause is that ::execute is called twice for document tab. But it would need some larger changes // to fix that, and with future syncs with qtopia 1.6 it will change anyway big time since somebody there // had the idea that an apploader belongs to the launcher ... //QCopEnvelope e("QPE/System", "notBusy(QString)" ); //e << ap; return; } #endif #ifdef QT_NO_QWS_MULTIPROCESS QMessageBox::warning( 0, "Error", "Could not find the application " + c, "Ok", 0, 0, 0, 1 ); #else QStrList slist; unsigned int j; for ( j = 0; j < list.count(); j++ ) slist.append( list[j].utf8() ); const char **args = new const char *[slist.count() + 1]; for ( j = 0; j < slist.count(); j++ ) args[j] = slist.at(j); + args[j] = NULL; #if !defined(QT_NO_COP) // an attempt to show a wait... // more logic should be used, but this will be fine for the moment... QCopEnvelope ( "QPE/System", "busy()" ); #endif #ifdef HAVE_QUICKEXEC #ifdef Q_OS_MACX QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".dylib"; #else QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".so"; #endif qDebug("libfile = %s", libexe.latin1() ); if ( QFile::exists( libexe ) ) { qDebug("calling quickexec %s", libexe.latin1() ); quickexecv( libexe.utf8().data(), (const char **)args ); } else #endif { bool success = false; int pfd [2]; if ( ::pipe ( pfd ) < 0 ) pfd [0] = pfd [1] = -1; pid_t pid = ::fork ( ); if ( pid == 0 ) { // child for ( int fd = 3; fd < 100; fd++ ) { if ( fd != pfd [1] ) ::close ( fd ); } ::setpgid ( ::getpid ( ), ::getppid ( )); // Closing of fd[1] indicates that the execvp succeeded! if ( pfd [1] >= 0 ) ::fcntl ( pfd [1], F_SETFD, FD_CLOEXEC ); // Try bindir first, so that foo/bar works too ::execv ( qpeDir ( ) + "/bin/" + args [0], (char * const *) args ); ::execvp ( args [0], (char * const *) args ); char resultByte = 1; if ( pfd [1] >= 0 ) ::write ( pfd [1], &resultByte, 1 ); ::_exit ( -1 ); } else if ( pid > 0 ) { success = true; if ( pfd [1] >= 0 ) ::close ( pfd [1] ); if ( pfd [0] >= 0 ) { while ( true ) { char resultByte; int n = ::read ( pfd [0], &resultByte, 1 ); if ( n == 1 ) { success = false; break; } if (( n == -1 ) && (( errno == ECHILD ) || ( errno == EINTR ))) continue; break; // success } ::close ( pfd [0] ); } } if ( success ) StartingAppList::add( list[0] ); else QMessageBox::warning( 0, "Error", "Could not start the application " + c, "Ok", 0, 0, 0, 1 ); } + delete [] args; #endif //QT_NO_QWS_MULTIPROCESS } /*! Executes the application identfied by \a c, passing \a document if it isn't null. Note that a better approach might be to send a QCop message to the application's QPE/Application/\e{appname} channel. */ void Global::execute( const QString &c, const QString& document ) { // ask the server to do the work #if !defined(QT_NO_COP) if ( document.isNull() ) { QCopEnvelope e( "QPE/System", "execute(QString)" ); e << c; } else { QCopEnvelope e( "QPE/System", "execute(QString,QString)" ); e << c << document; } #endif return; } /*! Returns the string \a s with the characters '\', '"', and '$' quoted by a preceeding '\'. \sa stringQuote() */ QString Global::shellQuote(const QString& s) { QString r="\""; for (int i=0; i<(int)s.length(); i++) { char c = s[i].latin1(); switch (c) { case '\\': case '"': case '$': r+="\\"; } r += s[i]; } r += "\""; return r; } /*! Returns the string \a s with the characters '\' and '"' quoted by a preceeding '\'. \sa shellQuote() */ QString Global::stringQuote(const QString& s) { QString r="\""; for (int i=0; i<(int)s.length(); i++) { char c = s[i].latin1(); switch (c) { case '\\': case '"': r+="\\"; } r += s[i]; } r += "\""; return r; } /*! Finds all documents on the system's document directories which match the filter \a mimefilter, and appends the resulting DocLnk objects to \a folder. */ void Global::findDocuments(DocLnkSet* folder, const QString &mimefilter) { QString homedocs = QString(getenv("HOME")) + "/Documents"; DocLnkSet d(homedocs,mimefilter); folder->appendFrom(d); /** let's do intellegint way of searching these files * a) the user don't want to check mediums global * b) the user wants to check but use the global options for it * c) the user wants to check it but not this medium * d) the user wants to check and this medium as well * * In all cases we need to apply a different mimefilter to * the medium. * a) mimefilter.isEmpty() we need to apply the responding filter * either the global or the one on the medium * * b) mimefilter is set to an application we need to find out if the * mimetypes are included in the mime mask of the medium */ StorageInfo storage; const QList<FileSystem> &fs = storage.fileSystems(); QListIterator<FileSystem> it ( fs ); for ( ; it.current(); ++it ) { if ( (*it)->isRemovable() ) { // let's find out if we should search on it // this is a candidate look at the cf and see if we should search on it QString path = (*it)->path(); Config conf((*it)->path() + "/.opiestorage.cf", Config::File ); conf.setGroup("main"); if (!conf.readBoolEntry("check",true)) { continue; } conf.setGroup("subdirs"); if (conf.readBoolEntry("wholemedia",true)) { DocLnkSet ide( path,mimefilter); folder->appendFrom(ide); } else { QStringList subDirs = conf.readListEntry("subdirs",':'); if (subDirs.isEmpty()) { subDirs.append("Documents"); } for (unsigned c = 0; c < subDirs.count();++c) { DocLnkSet ide( path+"/"+subDirs[c], mimefilter ); folder->appendFrom(ide); } } } else if ( (*it)->disk() == "/dev/mtdblock6" || (*it)->disk() == "tmpfs" ) { QString path = (*it)->path() + "/Documents"; DocLnkSet ide( path, mimefilter ); folder->appendFrom(ide); } } } QStringList Global::languageList() { QString lang = getenv("LANG"); QStringList langs; langs.append(lang); int i = lang.find("."); if ( i > 0 ) lang = lang.left( i ); i = lang.find( "_" ); if ( i > 0 ) langs.append(lang.left(i)); return langs; } QStringList Global::helpPath() { QString qpeDir = QPEApplication::qpeDir(); QStringList path; QStringList langs = Global::languageList(); for (QStringList::ConstIterator it = langs.fromLast(); it!=langs.end(); --it) { QString lang = *it; if ( !lang.isEmpty() ) path += qpeDir + "/help/" + lang + "/html"; } path += qpeDir + "/pics"; path += qpeDir + "/help/html"; /* we even put english into the en dir so try it as fallback as well for opie */ path += qpeDir + "/help/en/html"; path += qpeDir + "/docs"; return path; } /*! \internal Truncate file to size specified \a f must be an open file \a size must be a positive value */ bool Global::truncateFile(QFile &f, int size){ if (!f.isOpen()) return FALSE; return ::ftruncate(f.handle(), size) != -1; } // #if defined(Q_OS_UNIX) && defined(Q_WS_QWS) // extern int qws_display_id; // #endif /*! /internal Returns the default system path for storing temporary files. Note: This does not it ensure that the provided directory exists */ QString Global::tempDir() { QString result; #ifdef Q_OS_UNIX #ifdef Q_WS_QWS result = QString("/tmp/qtopia-%1/").arg(QString::number(qws_display_id)); #else result="/tmp/"; #endif #else if (getenv("TEMP")) result = getenv("TEMP"); else result = getenv("TMP"); if (result[(int)result.length() - 1] != QDir::separator()) result.append(QDir::separator()); #endif return result; } //#endif #include "global.moc" diff --git a/noncore/apps/opie-reader/Bkmks.cpp b/noncore/apps/opie-reader/Bkmks.cpp index 00141a3..45aa045 100644 --- a/noncore/apps/opie-reader/Bkmks.cpp +++ b/noncore/apps/opie-reader/Bkmks.cpp @@ -1,416 +1,417 @@ #include <qmessagebox.h> #include "Bkmks.h" #include "StyleConsts.h" #include "Markups.h" #include "my_list.h" #include "version.h" #include "names.h" const unsigned long BkmkFile::magic = ((unsigned long)'q' << 24) | ((unsigned long)'t' << 16) | ((unsigned long)'r' << 8) | ((unsigned long)BKMKTYPE); Bkmk::Bkmk(const unsigned char* _nm, unsigned short _nmlen, const unsigned char* _anno, unsigned short _annolen, unsigned int _p) : m_name(0), m_namelen(0), m_anno(0), m_annolen(0), m_position(0) { init(_nm, _nmlen, _anno, _annolen, _p); } Bkmk::Bkmk(const tchar* _nm, const unsigned char* _anno, unsigned short annolen, unsigned int _p) : m_position(_p) { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, annolen, _p); } Bkmk::Bkmk(const Bkmk& rhs) : m_name(0), m_namelen(0), m_anno(0), m_annolen(0), m_position(0) { init(rhs.name(), sizeof(tchar)*(ustrlen(rhs.name())+1), rhs.anno(), sizeof(tchar)*(ustrlen(rhs.anno())+1), rhs.value()); } Bkmk::Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p) : m_position(_p) { if (_anno == NULL) { tchar t = 0; init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), &t, sizeof(t), _p); } else { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, sizeof(tchar)*(ustrlen(_anno)+1), _p); } } Bkmk::Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p, unsigned int _p2) : m_position(_p) { if (_anno == NULL) { tchar t = 0; init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), &t, sizeof(t), _p); } else { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, sizeof(tchar)*(ustrlen(_anno)+1), _p); } m_position2 = _p2; m_red = m_green = m_blue = 127; } void Bkmk::init(const void* _nm, unsigned short _nmlen, const void* _anno, unsigned short _annolen, unsigned int _p) { m_namelen = _nmlen; if (m_namelen > 0) { m_name = new unsigned char[m_namelen]; memcpy(m_name, _nm, m_namelen); } else { m_name = NULL; } m_annolen = _annolen; if (m_annolen > 0) { m_anno = new unsigned char[m_annolen]; memcpy(m_anno, _anno, m_annolen); } else { m_anno = NULL; } m_position = _p; m_position2 = _p; m_red = m_green = m_blue = 255; m_level = 0; } Bkmk::~Bkmk() { if (m_name != NULL) delete [] m_name; m_name = NULL; if (m_anno != NULL) delete [] m_anno; m_anno = NULL; } Bkmk& Bkmk::operator=(const Bkmk& rhs) { if (m_name != NULL) { delete [] m_name; m_name = NULL; } if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (rhs.m_name != NULL) { m_namelen = rhs.m_namelen; m_name = new unsigned char[m_namelen]; memcpy(m_name, rhs.m_name, m_namelen); } else m_name = NULL; if (rhs.m_anno != NULL) { m_annolen = rhs.m_annolen; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, rhs.m_anno, m_annolen); } else m_anno = NULL; m_position = rhs.m_position; m_position2 = rhs.m_position2; m_red = rhs.m_red; m_green = rhs.m_green; m_blue = rhs.m_blue; m_level = rhs.m_level; return *this; } bool Bkmk::operator==(const Bkmk& rhs) { return ((m_position == rhs.m_position) && (m_position2 == rhs.m_position2) && (rhs.m_namelen == m_namelen) && memcmp(m_name,rhs.m_name,m_namelen) == 0); } void Bkmk::setAnno(unsigned char* t, unsigned short len) { if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (t != NULL) { m_annolen = len; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, t, m_annolen); } else { m_annolen = sizeof(tchar); m_anno = new unsigned char[m_annolen]; *((tchar*)m_anno) = 0; } } void Bkmk::setAnno(tchar* t) { if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (t != NULL) { unsigned short len = ustrlen(t)+1; m_annolen = sizeof(tchar)*len; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, t, m_annolen); } else { m_annolen = sizeof(tchar); m_anno = new unsigned char[m_annolen]; *((tchar*)m_anno) = 0; } } BkmkFile::BkmkFile(const char *fnm, bool w, bool _x) : wt(w), isUpgraded(false), m_extras(_x) { if (w) { f = fopen(fnm, "wb"); } else { f = fopen(fnm, "rb"); } } BkmkFile::~BkmkFile() { if (f != NULL) fclose(f); } void BkmkFile::write(const Bkmk& b) { if (f != NULL) { fwrite(&b.m_namelen, sizeof(b.m_namelen),1,f); fwrite(b.m_name,1,b.m_namelen,f); fwrite(&b.m_annolen, sizeof(b.m_annolen),1,f); fwrite(b.m_anno,1,b.m_annolen,f); fwrite(&b.m_position,sizeof(b.m_position),1,f); if (m_extras) { fwrite(&b.m_position2,sizeof(b.m_position2),1,f); fwrite(&b.m_red,sizeof(b.m_red),1,f); fwrite(&b.m_green,sizeof(b.m_green),1,f); fwrite(&b.m_blue,sizeof(b.m_blue),1,f); fwrite(&b.m_level,sizeof(b.m_level),1,f); } } } void BkmkFile::write(CList<Bkmk>& bl) { if (f != NULL) { fwrite(&magic, sizeof(magic), 1, f); for (CList<Bkmk>::iterator i = bl.begin(); i != bl.end(); i++) { write(*i); } } } CList<Bkmk>* BkmkFile::readall() { CList<Bkmk>* bl = NULL; if (f != NULL) { unsigned long newmagic; fread(&newmagic, sizeof(newmagic), 1, f); if ((newmagic & 0xffffff00) != (magic & 0xffffff00)) { if (QMessageBox::warning(NULL, "Old bookmark file!", "Which version of " PROGNAME "\ndid you upgrade from?", "0_4*", "Any other version") == 0) { fseek(f,0,SEEK_SET); bl = readall00(&read05); } else { fseek(f,0,SEEK_SET); bl = readall00(&read03); } isUpgraded = true; } else { switch(newmagic & 0xff) { case 7: isUpgraded = false; bl = readall00(read07); // qDebug("Correct version!"); break; case 6: isUpgraded = true; bl = readall00(read06); // qDebug("Correct version!"); break; case 5: isUpgraded = true; bl = readall00(read05); // qDebug("Known version!"); break; default: // qDebug("Unknown version!"); isUpgraded = true; bl = readall00(read05); } } } return bl; } CList<Bkmk>* BkmkFile::readall00(Bkmk* (*readfn)(BkmkFile*, FILE*)) { CList<Bkmk>* bl = new CList<Bkmk>; while (1) { Bkmk* b = (*readfn)(this, f); if (b == NULL) break; bl->push_back(*b); delete b; } return bl; } Bkmk* BkmkFile::read03(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { tchar* name = new tchar[ln+1]; fread(name,sizeof(tchar),ln,f); name[ln] = 0; ln = 0; tchar* anno = new tchar[ln+1]; anno[ln] = 0; unsigned int pos; fread(&pos,sizeof(pos),1,f); b = new Bkmk(name,anno,pos); delete [] anno; } } return b; } Bkmk* BkmkFile::read05(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { tchar* nm = new tchar[ln+1]; fread(nm,sizeof(tchar),ln,f); nm[ln] = 0; fread(&ln,sizeof(ln),1,f); tchar* anno = new tchar[ln+1]; if (ln > 0) fread(anno,sizeof(tchar),ln,f); anno[ln] = 0; unsigned int pos; fread(&pos,sizeof(pos),1,f); b = new Bkmk(nm,anno,pos); + delete [] anno; } } return b; } Bkmk* BkmkFile::read06(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { b = new Bkmk; b->m_namelen = ln; b->m_name = new unsigned char[b->m_namelen]; fread(b->m_name,1,b->m_namelen,f); fread(&(b->m_annolen),sizeof(b->m_annolen),1,f); if (b->m_annolen > 0) { b->m_anno = new unsigned char[b->m_annolen]; fread(b->m_anno,1,b->m_annolen,f); } fread(&(b->m_position),sizeof(b->m_position),1,f); b->m_position2 = b->m_position+b->m_namelen-1; b->m_red = b->m_green = b->m_blue = 127; b->m_level = 0; } } return b; } Bkmk* BkmkFile::read07(BkmkFile* _this, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { b = new Bkmk; b->m_namelen = ln; b->m_name = new unsigned char[b->m_namelen]; fread(b->m_name,1,b->m_namelen,f); fread(&(b->m_annolen),sizeof(b->m_annolen),1,f); if (b->m_annolen > 0) { b->m_anno = new unsigned char[b->m_annolen]; fread(b->m_anno,1,b->m_annolen,f); } fread(&(b->m_position),sizeof(b->m_position),1,f); if (_this->m_extras) { fread(&(b->m_position2),sizeof(b->m_position2),1,f); fread(&(b->m_red),sizeof(b->m_red),1,f); fread(&(b->m_green),sizeof(b->m_green),1,f); fread(&(b->m_blue),sizeof(b->m_blue),1,f); fread(&(b->m_level),sizeof(b->m_level),1,f); } else { b->m_position2 = b->m_position; b->m_red = b->m_green = b->m_blue = 255; b->m_level = 0; } } } return b; } diff --git a/noncore/apps/opie-sheet/Excel.cpp b/noncore/apps/opie-sheet/Excel.cpp index 51fe707..27080e9 100644 --- a/noncore/apps/opie-sheet/Excel.cpp +++ b/noncore/apps/opie-sheet/Excel.cpp @@ -1,1709 +1,1711 @@ /* =. This file is part of the Opie Project .=l. Copyright (C) 2004 Opie Developer Team <opie-devel@handhelds.org> .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. 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 ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Excel.h" /* STD */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <sys/types.h> #include <strings.h> static xfrecord formatter[] = { { 0xe , DATEFORMAT, "%m/%d/%y"}, { 0xf , DATEFORMAT, "%d-%b-%y"}, { 0x10, DATEFORMAT, "%d-%b"}, { 0x11, DATEFORMAT, "%b-%y"}, { 0x12, DATEFORMAT, "%I:%M %p"}, { 0x13, DATEFORMAT, "%I:%M:%S %p"}, { 0x14, DATEFORMAT, "%H:%M"}, { 0x15, DATEFORMAT, "%H:%M:%S"}, { 0x16, DATEFORMAT, "%m/%d/%y %H:%M"}, { 0x2d, DATEFORMAT, "%M:%S"}, { 0x2e, DATEFORMAT, "%H:%M:%S"}, { 0x2f, DATEFORMAT, "%M:%S"}, { 0xa5, DATEFORMAT, "%m/%d/%y %I:%M %p"}, { 0x1 , NUMBERFORMAT, "%.0f"}, { 0x2 , NUMBERFORMAT, "%.2f"}, { 0x3 , NUMBERFORMAT, "#,##%.0f"}, { 0x4 , NUMBERFORMAT, "#,##%.2f"}, { 0x5 , NUMBERFORMAT, "$#,##%.0f"}, { 0x6 , NUMBERFORMAT, "$#,##%.0f"}, { 0x7 , NUMBERFORMAT, "$#,##%.2f"}, { 0x8 , NUMBERFORMAT, "$#,##%.2f"}, { 0x9 , NUMBERFORMAT, "%.0f%%"}, { 0xa , NUMBERFORMAT, "%.2f%%"}, { 0xb , NUMBERFORMAT, "%e"}, { 0x25, NUMBERFORMAT, "#,##%.0f;(#,##0)"}, { 0x26, NUMBERFORMAT, "#,##%.0f;(#,##0)"}, { 0x27, NUMBERFORMAT, "#,##%.2f;(#,##0.00)"}, { 0x28, NUMBERFORMAT, "#,##%.2f;(#,##0.00)"}, { 0x29, NUMBERFORMAT, "#,##%.0f;(#,##0)"}, { 0x2a, NUMBERFORMAT, "$#,##%.0f;($#,##0)"}, { 0x2b, NUMBERFORMAT, "#,##%.2f;(#,##0.00)"}, { 0x2c, NUMBERFORMAT, "$#,##%.2f;($#,##0.00)"}, { 0x30, NUMBERFORMAT, "##0.0E0"}, { 0, 0, ""} }; int ExcelBook::Integer2Byte(int b1, int b2) { int i1 = b1 & 0xff; int i2 = b2 & 0xff; int val = i2 << 8 | i1; return val; }; int ExcelBook::Integer4Byte(int b1,int b2,int b3,int b4) { int i1 = Integer2Byte(b1, b2); int i2 = Integer2Byte(b3, b4); int val = i2 << 16 | i1; return val; }; int ExcelBook::Integer2ByteFile(FILE *f) { int i1, i2; i1 = fgetc(f); i2 = fgetc(f); return Integer2Byte(i1,i2); }; float ExcelBook::Float4Byte(int b1, int b2, int b3, int b4) { int i; float f; unsigned char *ieee; ieee = (unsigned char *) &f; for (i = 0; i < 4; i++) ieee[i] = 0; ieee[0] = ((int)b4) & 0xff; ieee[1] = ((int)b3) & 0xff; ieee[2] = ((int)b2) & 0xff; ieee[3] = ((int)b1) & 0xff; return f; }; double ExcelBook::Double4Byte(int b1, int b2, int b3, int b4) { long int rk; double value; rk=Integer4Byte(b1,b2,b3,b4); //printf("Double4Bytes:%d,%d,%d,%d\r\n",b1,b2,b3,b4); if ( (rk & 0x02) != 0) { long int intval = rk >> 2; //drops the 2 bits printf("Double4Byte:intval=%d, rk=%d, rk>>2=%d\r\n",intval,rk,rk>>2); value = (double) intval; printf("Double4Byte: VALUEINT=%f\r\n",value); if ( (rk & 0x01) != 0) { value /= 100.0; }; return value; } else { union { double d; unsigned long int b[2]; } dbl_byte; unsigned long int valbits = (rk & 0xfffffffc); #if defined(__arm__) && !defined(__vfp__) dbl_byte.b[0]=valbits; dbl_byte.b[1]=0; #else dbl_byte.b[0]=0; dbl_byte.b[1]=valbits; #endif printf("dbl_byte.b[0]=%d,dbl_byte.b[1]=%d\r\n",dbl_byte.b[0],dbl_byte.b[1]); value=dbl_byte.d; printf("Double4Byte: VALUE=%f\r\n",value); if ( (rk & 0x01) != 0) { value /= 100.0; }; return value; }; }; void ExcelBook::DetectEndian(void) { int end; long i = 0x44332211; unsigned char* a = (unsigned char*) &i; end = (*a != 0x11); if (end == 1) { endian = BIG_ENDIAN; printf("BIGENDIAN!\r\n"); } else { endian = LITTLE_ENDIAN; printf("LITTLEENDIAN!\r\n"); } }; double ExcelBook::Double8Byte(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8) { int i; double d; unsigned char *ieee; ieee = (unsigned char *)&d; for (i = 0; i < 8; i++) ieee[i] = 0; if (endian == BIG_ENDIAN) { ieee[0] = ((int)b8) & 0xff;ieee[1] = ((int)b7) & 0xff; ieee[2] = ((int)b6) & 0xff;ieee[3] = ((int)b5) & 0xff; ieee[4] = ((int)b4) & 0xff;ieee[5] = ((int)b3) & 0xff; ieee[6] = ((int)b2) & 0xff;ieee[7] = ((int)b1) & 0xff; } else { ieee[0] = ((int)b1) & 0xff;ieee[1] = ((int)b2) & 0xff; ieee[2] = ((int)b3) & 0xff;ieee[3] = ((int)b4) & 0xff; ieee[4] = ((int)b5) & 0xff;ieee[5] = ((int)b6) & 0xff; ieee[6] = ((int)b7) & 0xff;ieee[7] = ((int)b8) & 0xff; } return d; }; bool ExcelBook::OpenFile(char *Filename) { printf("Opening excel file!\r\n"); File= fopen(Filename, "r"); Position=0; // first byte index in file XFRecords.resize(0); SharedStrings.resize(0); Names.resize(0); Sheets.resize(0); if(File==NULL) return false; printf("Opened excel file!\r\n"); return true; }; bool ExcelBook::CloseFile(void) { int w1; for(w1=0;w1<(int)XFRecords.count();w1++) { if(XFRecords[w1]!=NULL) {delete XFRecords[w1];XFRecords[w1]=NULL;}; }; for(w1=0;w1<(int)SharedStrings.count();w1++) { if(SharedStrings[w1]!=NULL) {delete SharedStrings[w1];SharedStrings[w1]=NULL;}; }; for(w1=0;w1<(int)Names.count();w1++) { if(Names[w1]!=NULL) {delete Names[w1];Names[w1]=NULL;}; }; for(w1=0;w1<(int)Sheets.count();w1++) { if(Sheets[w1]!=NULL) {delete Sheets[w1];Sheets[w1]=NULL;}; }; XFRecords.resize(0); SharedStrings.resize(0); Names.resize(0); Sheets.resize(0); fclose(File); printf("closed excel file!\r\n"); if(File==NULL) return true; return false; }; void ExcelBook::SeekPosition(int pos) { if(!feof(File)) { Position=pos; //printf("SeekPosition:Pos:%d\r\n",Position); fseek(File,pos,SEEK_SET); }; }; void ExcelBook::SeekSkip(int pos) { if(!feof(File)) { Position=Position+pos; //printf("SeekSkip:Pos:%d\r\n",Position); fseek(File, Position, SEEK_SET); }; }; int ExcelBook::FileEOF(void) { if(File!=NULL) return(feof(File)); else return 0; //EOF is defined in stdlib as -1 }; int ExcelBook::Get2Bytes(void) { int i1,i2; i1=0; i2=0; if (!feof(File)) { i1=fgetc(File); Position++; }; if (!feof(File)) { i2=fgetc(File); Position++; }; return Integer2Byte(i1,i2); }; char* ExcelBook::Read(int pos, int length) { int i; char *data; data= new char[length]; SeekPosition(pos); for(i=0; i<length; i++) { if(!feof(File)) data[i]=fgetc(File); }; Position= Position+length; return data; }; QString ExcelBook::ReadUnicodeChar(int pos, int length) { int i; QString data; int i1=' ',i2=' ',ii; SeekPosition(pos); for(i=0; i<length; i++) { if(!feof(File)) i1=fgetc(File); if(!feof(File)) i2=fgetc(File); ii=Integer2Byte(i1,i2); data.append(ii); Position+=2; }; return data; }; QString* ExcelBook::GetString(int num) { if(num>=0 && num<(int)SharedStrings.count()) { return SharedStrings[num]; }; return new QString(""); }; int ExcelBook::SeekBOF(void) { int opcode,version,streamtype,length,ret=0; char *data; while(!feof(File)) { opcode=Get2Bytes(); if(opcode==XL_BOF) { length=Get2Bytes(); data=Read(Position,length); version=Integer2Byte(data[0], data[1]); streamtype=Integer2Byte(data[2], data[3]); printf("SEEKBOF:opcode=XLBOF, %d ,version %d\r\n",Position,version); delete [] data; data=NULL; if (version==BIFF8) ret=8; else if(version==BIFF7) ret=7; printf("SEEKBOF:versionBIFF%d\r\n",ret); if(streamtype==WBKGLOBAL) return ret *2; else if(streamtype==WRKSHEET) return ret *1; return 1; }; }; return 0; }; ExcelBREC* ExcelBook::GetBREC(void) { ExcelBREC* rec; rec= new ExcelBREC; if(FileEOF()) return NULL; rec->data=NULL; rec->code=Get2Bytes(); rec->length=Get2Bytes(); rec->position=Position; SeekSkip(rec->length); return rec; }; ExcelBREC* ExcelBook::PeekBREC(void) { int oldpos; ExcelBREC* NextRec; oldpos=Position; NextRec=GetBREC(); SeekPosition(oldpos); return NextRec; }; char* ExcelBook::GetDataOfBREC(ExcelBREC* record) { if(record->data==NULL) { - ConvertCharToArray(record,Read(record->position,record->length),record->length); + char* readData = Read(record->position,record->length); + ConvertCharToArray(record,readData,record->length); + delete [] readData; }; return record->data;//new? }; void ExcelBook::ConvertCharToArray(ExcelBREC* record, char* chars, int length) { record->data=new char[length]; for(int w1=0;w1<=length-1;w1++) record->data[w1]=chars[w1]; }; bool ExcelSheet::InitCells() { int r; Cells.resize(rows * cols + cols+1); if(Cells.count()==0) return false; for(r=0;r < Cells.count();r++) { Cells[r]=NULL; }; return true; }; void ExcelSheet::Set(int row, int col, ExcelCell* cell) { if(cell!=NULL&&(row*cols+col)<Cells.count()) { Cells[row*cols+col]=cell; }; }; ExcelCell* ExcelSheet::Get(int row, int col) { ExcelCell* cell; cell=Cells[row*cols+col]; if(cell==NULL) return NULL; return cell; }; int ExcelBook::SheetHandleRecord(ExcelSheet* sheet, ExcelBREC* record) { char* data=NULL; switch (record->code) { case XL_DIMENSION: data = GetDataOfBREC(record); if (record->length == 10) { sheet->rows = Integer2Byte(data[2], data[3]); sheet->cols = Integer2Byte(data[6], data[7]); } else { sheet->rows = Integer4Byte(data[4], data[5], data[6], data[7]); sheet->cols = Integer2Byte(data[10], data[11]); } sheet->InitCells(); break; case XL_LABELSST: HandleLabelSST(sheet, record); break; case XL_RK: case XL_RK2: HandleRK(sheet, record); break; case XL_MULRK: HandleMulrk(sheet, record); break; case XL_ROW: break; case XL_NUMBER: HandleNumber(sheet, record); break; case XL_BOOLERR: break; case XL_CONTINUE: break; case XL_FORMULA: case XL_FORMULA2: HandleFormula(sheet, record); break; case XL_LABEL: break; case XL_NAME: HandleName(sheet, record); break; case XL_BOF: break; case XL_EOF: return 0; default: break; }; return 1; }; int ExcelBook::ReadSheet(ExcelSheet* sheet) { ExcelBREC* record; int oldpos; oldpos = Position; SeekPosition(sheet->position); record = GetBREC(); while (record!=NULL) { if (!SheetHandleRecord(sheet, record)) break; record=GetBREC(); }; SeekPosition(oldpos); return 1; }; ExcelSheet* ExcelBook::GetSheet(void) { ExcelSheet* sh=NULL; int type; type=SeekBOF(); Version=type; sh=new ExcelSheet; if(type) { sh->type=type; sh->position=Position; sh->name=QString(""); }; if(type==8||type==7) { ReadSheet(sh); }; return sh; }; void ExcelBook::ParseSheets(void) { int BOFs; ExcelBREC* r; BOFs=1; r=GetBREC(); while(BOFs) { r=GetBREC(); switch(r->code) { case XL_SST: HandleSST(r); break; case XL_TXO: break; case XL_NAME: break; case XL_ROW: break; case XL_FORMAT: HandleFormat(r); break; case XL_XF: HandleXF(r); break; case XL_BOUNDSHEET: HandleBoundSheet(r); break; case XL_EXTSST: break; case XL_CONTINUE: break; case XL_EOF: BOFs--; break; default: break; }; }; }; void ExcelBook::GetSheets(void) { ExcelSheet* sheet; Sheets.resize(0); sheet=GetSheet(); while (sheet->Cells.count()!= 0 ) { Sheets.resize(Sheets.count()+1); Sheets[Sheets.count()-1]=sheet; sheet->name=*Names[Sheets.count()-1]; sheet=GetSheet(); }; }; bool ExcelBook::ParseBook(char *file) { dateformat=QString(""); DetectEndian(); if ( !OpenFile( file ) ) return false; SeekBOF(); ParseSheets(); GetSheets(); return true; }; QString ExcelBook::GetASCII(char* inbytes, int pos, int chars) { int i; QString outstr=""; for (i = 0; i < chars; i++) { outstr.append(inbytes[i+pos]); }; return outstr; }; QString ExcelBook::GetUnicode(char * inbytes, int pos, int chars) { QString outstr=""; int i; int rc; for (i=0; i<chars*2; i++) { rc=Integer2Byte(inbytes[i+pos],inbytes[i+pos+1]); outstr.append(QChar(rc)); i++; }; return outstr; }; void ExcelBook::HandleBoundSheet(ExcelBREC* rec) { char* data; int type; int visibility; int length; int pos; QString name; pos = 8; data = GetDataOfBREC(rec); type = data[4]; visibility = data[5]; length = data[6]; if(data[7]==0) { //ascii name=GetASCII(data,pos,length); } else { name=GetUnicode(data,pos,length); }; Names.resize(Names.count()+1); Names[Names.count()-1]=new QString(name); }; void ExcelBook::HandleName(ExcelSheet* sheet, ExcelBREC* rec) { char* data; QString name; int length; int pos; pos = 15; data = GetDataOfBREC(rec); length = data[3]; name = GetASCII(data,pos,length); }; ExcelFormat* ExcelBook::GetFormatting(int xf) { int i; ExcelFormat* rec; rec=new ExcelFormat(); for (i = 0; formatter[i].code != 0; i++) { if (xf == formatter[i].code) break; }; if (formatter[i].format ==NULL) return NULL; rec->code = xf; rec->type = formatter[i].type; rec->format = formatter[i].format; return rec; }; void ExcelBook::HandleSetOfSST(ExcelBREC* rec/*, SSTList* cont*/, char* bytes) { QString str=QString(""); char* data; int chars, pos, options, i; int richstring, fareaststring, runlength=0; int richruns=0,fareastsize=0; int totalstrings; int uniquestrings; data = GetDataOfBREC(rec); totalstrings = Integer4Byte(data[0], data[1], data[2], data[3]); uniquestrings = Integer4Byte(data[4], data[5], data[6], data[7]); pos = 8; for (i = 0; i < uniquestrings; i++) { richruns=0; fareastsize=0; chars = Integer2Byte(data[pos], data[pos+1]); pos += 2; options = data[pos]; pos++; fareaststring = ((options & 0x04) != 0); richstring = ((options & 0x08) != 0); if(richstring) { richruns= Integer2Byte(data[pos],data[pos+1]); pos+=2; }; if(fareaststring) { fareastsize=Integer4Byte(data[pos], data[pos+1], data[pos+2], data[pos+3]); pos+=4; }; if ((options & 0x01) == 0) //8 bit chars { /* ascii */ str = GetASCII(bytes,pos,chars); pos=pos+chars; if(str[0]=='=') str[0]=' '; }else //16 bit chars { /* unicode */ str = GetUnicode(bytes,pos,chars); pos=pos+chars*2; }; // HERE TO PUT richformat handling if (richstring) { pos += 4 * richruns; }; if (fareaststring) { pos += fareastsize; }; //printf("String=%s, length=%d first=0x%x\r\n",str.ascii(),str.length(),str[0].unicode()); SharedStrings.resize(SharedStrings.count()+1); SharedStrings[SharedStrings.count()-1]=new QString(str); } }; char* ExcelBook::MergeBytesFromSSTs(ExcelBREC* rec,SSTList* cont) { int i, pos; int length; char* data; char* bytes; length = rec->length; for (i = 0; i < (int) cont->rec.count(); i++) { length += cont->rec[i]->length; } bytes = GetDataOfBREC(rec); pos = rec->length; for (i = 0; i < (int) cont->rec.count(); i++) { data = GetDataOfBREC(cont->rec[i]); *bytes += pos; bytes = data; pos += cont->rec[i]->length; } return bytes; }; void ExcelBook::HandleSST(ExcelBREC* rec) { char* bytes; SSTList* cont; cont= new SSTList; ExcelBREC* nr; nr = PeekBREC(); while (nr->code == XL_CONTINUE) { cont->rec.resize(cont->rec.count()+1); cont->rec[cont->rec.count()-1]=GetBREC(); nr = PeekBREC(); } bytes = MergeBytesFromSSTs(rec,cont); HandleSetOfSST(rec, bytes); for(int w1=0;w1<(int)cont->rec.count();w1++) { if(cont->rec[w1]!=NULL) {delete cont->rec[w1];cont->rec[w1]=NULL;}; }; cont->rec.resize(0); }; void ExcelBook::HandleLabelSST(ExcelSheet* sheet, ExcelBREC* rec) { int index, row, col; char* data; data = GetDataOfBREC(rec); index = Integer4Byte(data[6], data[7], data[8], data[9]); row = Integer2Byte(data[0], data[1]); col = Integer2Byte(data[2], data[3]); sheet->Set(row,col, CellLabel(row, col, *GetString(index))); }; ExcelCell* ExcelBook::CellLabel(int row, int col, QString str) { ExcelCell* c; c= new ExcelCell; c->row = row; c->col = col; c->type = CELL_LABEL; c->valuec = str; return c; }; ExcelCell* ExcelBook::CellNumber(int row, int col, int index, double d) { ExcelCell* c; c=new ExcelCell; c->row = row; c->col = col; c->xfindex = index; c->type = CELL_NUMBER; c->valued = d; return c; }; QString* ExcelBook::CellDataString(ExcelSheet* sh, int row, int col) { time_t date; struct tm *tmptr; ExcelCell* c; char str[128]; QString format; int precision; int utcOffsetDays = 25569; int sInADay = 24 * 60 * 60; c = sh->Get(row,col); if (c == NULL) return new QString(""); switch (c->type) { case CELL_LABEL: return new QString(c->valuec); case CELL_NUMBER: if (XFRecords[c->xfindex]->type == DATEFORMAT) { format = XFRecords[c->xfindex]->format; date = (time_t) ((c->valued - utcOffsetDays) * sInADay); tmptr = gmtime(&date); if (dateformat) { strftime(str,1024,dateformat.ascii(),tmptr); } else { strftime(str,1024,format.ascii(),tmptr); }; } else if (XFRecords[c->xfindex]->type == NUMBERFORMAT) { format = XFRecords[c->xfindex]->format; //sprintf(str,format.ascii(),c->valued); // the real format is ignored... // because there is more work to be done in the field precision = CellGetPrecision(c->valued); sprintf(str,"%.*f",precision,c->valued); } else { precision = CellGetPrecision(c->valued); sprintf(str,"%.*f",precision,c->valued); }; break; case CELL_DATE: break; case CELL_BOOLEAN: break; case CELL_ERROR: break; } return new QString(str); }; int ExcelBook::CellGetPrecision(double d) { double t; int i,x; int count; if (d < 0) d *= -1; i = (int)d; t = d - (double)i; if (t <= 0) { return 0; }; count = 0; for (x = 6; x > 1; x--) { i = (int)d; t = d - (double)i; t *= pow(10,x - 2); i = (int)t; t = t - (double)i; t *= 10; i = (int)t; if (i > 0) break; count++; }; return (5 - count); }; void ExcelBook::CellSetDateFormat(char *d) { dateformat = QString(d); }; void ExcelBook::HandleMulrk(ExcelSheet* sheet, ExcelBREC* record) { struct mulrk mulrk; char* data; ExcelCell* cell; int len; int i; len = record->length; data = GetDataOfBREC(record); mulrk.row = Integer2Byte(data[0],data[1]); mulrk.first = Integer2Byte(data[2],data[3]); mulrk.last = Integer2Byte(data[len - 2],data[len - 1]); mulrk.numrks = mulrk.last - mulrk.first + 1; MulrkRead(&mulrk, data); for (i = 0; i < mulrk.numrks; i++) { cell = CellNumber(mulrk.row, mulrk.first + i, mulrk.xfindices[i], mulrk.rkdbls[i]); sheet->Set(mulrk.row,mulrk.first+ i, cell); //printf("handleMULRK:row=%d,col=%d,val=%f\r\n",mulrk.row,mulrk.first+i,mulrk.rkdbls[i]); } //delete(mulrk.xfindices); //delete(mulrk.rkdbls); }; void ExcelBook::MulrkRead(struct mulrk *mulrk, char* data) { double d; int i; int pos; pos = 4; mulrk->xfindices.resize(mulrk->numrks); mulrk->rkdbls.resize(mulrk->numrks); for (i = 0; i < mulrk->numrks; i++) { mulrk->xfindices[i] = Integer2Byte(data[pos], data[pos+1]); d=Double4Byte(data[pos+2], data[pos+3], data[pos+4], data[pos+5]); //printf("double:%f\r\n",d); mulrk->rkdbls[i] = d; pos += 6; } }; void ExcelBook::HandleNumber(ExcelSheet* sheet, ExcelBREC* record) { int xfindex, row, col; char* data; double d; data = GetDataOfBREC(record); row = Integer2Byte(data[0], data[1]); col = Integer2Byte(data[2], data[3]); xfindex = Integer2Byte(data[4], data[5]); #if defined(__arm__) && !defined(__vfp__) d=Double8Byte(data[10], data[11], data[12], data[13],data[6], data[7], data[8], data[9]); #else d=Double8Byte(data[6], data[7], data[8], data[9],data[10], data[11], data[12], data[13]); #endif //even if ARM is little endian... doubles are been placed as bigendian words. //thanks pb_ for that. :) sheet->Set(row,col, CellNumber(row,col,xfindex,d)); //printf("handleNumber:row=%d,col=%d,val=%f\r\n",row,col,d); }; ExcelFormat::ExcelFormat() { code=0;type=0;format=""; }; ExcelFormat::ExcelFormat(int c,int t, QString s) { code=c;type=t;format=s; }; void ExcelBook::HandleFormat(ExcelBREC* rec) { ExcelFormat* xfrec; char* data; int format; data = GetDataOfBREC(rec); format = Integer2Byte(data[2],data[3]); xfrec = GetFormatting(format); /*int idx; idx=XFRecords.count()-1; XFRecords[idx]->code=xfrec->code; XFRecords[idx]->type=xfrec->type; XFRecords[idx]->format="manos"; //XFRecords[XFRecords.count()-1]=xfrec; printf("6\r\n");*/ }; void ExcelBook::HandleXF(ExcelBREC* rec) { ExcelFormat* xfrec; char* data; int format; data = GetDataOfBREC(rec); format = Integer2Byte(data[2],data[3]); xfrec = GetFormatting(format); XFRecords.resize(XFRecords.count()+1); XFRecords[XFRecords.count()-1]=xfrec; }; void ExcelBook::HandleRK(ExcelSheet* sheet, ExcelBREC* record) { int xfindex, row, col; char* data; double d; data = GetDataOfBREC(record); row = Integer2Byte(data[0], data[1]); col = Integer2Byte(data[2], data[3]); xfindex = Integer2Byte(data[4], data[5]); d=Double4Byte(data[6], data[7], data[8], data[9]); sheet->Set(row,col,CellNumber(row,col,xfindex,d)); //printf("handleRK:row=%d,col=%d,val=%f\r\n",row,col,d); }; void ExcelBook::HandleFormula(ExcelSheet* sheet, ExcelBREC* record) { int xfindex, row, col; char* data; double d; data = GetDataOfBREC(record); row = Integer2Byte(data[0], data[1]); col = Integer2Byte(data[2], data[3]); if (data[6] == 0 && data[12] == -1 && data[13] == -1) { // string } else if (data[6] == 1 && data[12] == -1 && data[13] == -1) { // boolean } else if ( data[6] == 2 && data[12] == -1 && data[13] == -1) { // error } else { // number xfindex = Integer2Byte(data[4], data[5]); d=Double8Byte(data[6], data[7], data[8], data[9],data[10], data[11], data[12], data[13]); QString s1; int sz; sz=Integer2Byte(data[20],data[21]);// size of the formula char* formuladata; formuladata=new char[sz]; for(int w1=0;w1<sz;w1++) { formuladata[w1]=data[22+w1]; }; //22 is the first 0 idx of formula data s1="="+GetFormula(row,col,sheet,formuladata,sz); //printf("GetFormula:Formula=%s\r\n",s1.ascii()); sheet->Set(row,col,CellLabel(row,col,s1)); } }; QString ExcelBook::GetFormula(int row, int col, ExcelSheet* sheet, char* data, int sz) { int length=sz; printf("{FormulaParser}\r\n"); printf("row=%d, col=%d, length=%d\r\n",row,col,length); int idx=0; int w1,w2,w3,w4; double d1; int token; QString s1; QList <QString> operands; operands.setAutoDelete(TRUE); QString formula; operands.clear(); while( idx<length ) { token= data[idx]; idx++; switch(token) { case 0x1E: //prtInt w1=Integer2Byte(data[idx],data[idx+1]); idx=idx+2; operands.prepend(new QString(QString::number(w1))); printf(" token:ptgInt,num=%d\r\n",w1); break; case 0x1F: //ptgNumber #if defined(__arm__) && !defined(__vfp__) d1=Double8Byte(data[idx+4],data[idx+5],data[idx+6],data[idx+7] ,data[idx],data[idx+1],data[idx+2],data[idx+3]); #else d1=Double8Byte(data[idx],data[idx+1],data[idx+2],data[idx+3] ,data[idx+4],data[idx+5],data[idx+6],data[idx+7]); #endif idx=idx+8; operands.prepend(new QString(QString::number(d1))); printf(" token:ptgNumber,num=%f\r\n",d1); break; case 0x17: //ptgStr if(Version==8) { //unicode string //w1=Integer2Byte(data[idx],data[idx+1]);idx+=2; w1=data[idx];idx++; printf("len=%d\r\n",w1); int richruns=0; int fareastsize=0; int richstring,fareaststring; int options = data[idx];idx++; fareaststring = ((options & 0x04) != 0); richstring = ((options & 0x08) != 0); if(richstring) { //containts rich string formatting. printf("STRING:richstring\r\n"); richruns= Integer2Byte(data[idx],data[idx+1]); printf("richruns:%d\r\n",richruns); idx+=2; }; if(fareaststring) { //contains far east formatting printf("STRING:fareast!\r\n"); fareastsize=Integer4Byte(data[idx], data[idx+1], data[idx+2], data[idx+3]); printf("fareastsize=%d",fareastsize); idx+=4; }; if ((options & 0x01) == 0) //8 bit chars { /* ascii */ s1 = GetASCII(data,idx,w1); idx=idx+w1; printf("STRING:ASCII=%s\r\n",s1.ascii()); }else //16 bit chars { /* unicode */ s1 = GetUnicode(data,idx,w1); idx=idx+w1*2; printf("STRING:unicode=%s\r\n",s1.ascii()); }; // HERE TO PUT richformat handling if (richstring) { idx += 4 * richruns; }; if (fareaststring) { idx += fareastsize; }; s1=QString("""")+s1+QString(""""); operands.prepend(new QString(s1)); } else { w1=data[idx];idx++; s1=GetASCII(data,idx,w1); s1=QString("""")+s1+QString(""""); idx=idx+w1; operands.prepend(new QString(s1)); }; printf(" token:ptgStr,num=%d\r\n",w1); break; case 0x25: case 0x45: case 0x65: // ptgArea if(Version==8) { w1=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//row1 w2=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//row2 w3=Integer2Byte(data[idx],data[idx+1]) & 0x00FF;idx=idx+2;//col1 w4=Integer2Byte(data[idx],data[idx+1]) & 0x00FF;idx=idx+2;//col2 } else { w1=Integer2Byte(data[idx],data[idx+1]) & 0x3FFF;idx=idx+2;//row1 w2=Integer2Byte(data[idx],data[idx+1]) & 0x3FFF;idx=idx+2;//row2 w3=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//col1 w4=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//col2 }; //ignores relative or absolute refs s1=FindCellName(w1,w3)+":"+FindCellName(w2,w4); printf(" token:ptgArea,ref=%s\r\n",s1.ascii()); operands.prepend(new QString(s1)); break; case 0x24: case 0x44: case 0x64://ptgRef if(Version==8) { w1=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//row w2=Integer2Byte(data[idx],data[idx+1]) & 0x00FF;idx=idx+2;//col } else { w1=Integer2Byte(data[idx],data[idx+1]) & 0x3FFF;idx=idx+2;//row w2=Integer2Byte(data[idx],data[idx+1]);idx=idx+2;//col }; s1=FindCellName(w1,w2); printf("token:ptgRef,ref=%s\r\n",s1.ascii()); operands.prepend(new QString(s1)); break; case 0x1D: // ptgBool w1=data[idx];idx++; printf("token:ptgBool,val=%d\r\n",w1); operands.prepend(new QString(QString::number(w1))); break; case 0x16://ptg MissArg printf("token:ptgMissArg, val=' '\r\n"); operands.prepend(new QString("0")); break; case 0x12://ptgUplus== printf("token:ptgUplus\r\n"); s1=QString("+")+operands.first()->ascii(); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x13://ptgUminus printf("token:ptgUminus\r\n"); s1=QString("-")+operands.first()->ascii(); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x03://ptgAdd printf("token:ptgAdd\r\n"); operands.first(); s1=operands.next()->ascii() +QString("+")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x04://ptgSub printf("token:ptgSub\r\n"); operands.first(); s1=operands.next()->ascii() +QString("-")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x05://ptgMul printf("token:ptgMul\r\n"); operands.first(); s1=operands.next()->ascii() +QString("*")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x06://ptgDiv printf("token:ptgDiv\r\n"); operands.first(); s1=operands.next()->ascii() +QString("/")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x07://ptgPOWER printf("token:ptgPow\r\n"); operands.first(); s1=QString("POWER(")+operands.next()->ascii() +QString(",")+operands.first()->ascii()+QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x08://ptgConcat printf("token:ptgConcat\r\n"); operands.first(); s1=QString("CONCATENATE(")+operands.next()->ascii() +QString(",")+operands.first()->ascii()+QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x15://ptgParenthesis printf("token:ptgParenthesis\r\n"); s1=QString("(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x14://ptgPercent printf("token:ptgPercent\r\n"); s1=operands.first()->ascii()+QString("*0.01"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x9://ptgLessThan printf("token:ptgLESS\r\n"); operands.first(); s1=operands.next()->ascii() +QString("<")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xa://ptgLessEqual printf("token:ptgLESS_EQUAL\r\n"); operands.first(); s1=operands.next()->ascii() +QString("<=")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xb://ptgEQUAL printf("token:ptgEQUAL\r\n"); operands.first(); s1=operands.next()->ascii() +QString("==")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xc://ptgGREATER_EQUAL printf("token:ptgGREAT_EQUAL\r\n"); operands.first(); s1=operands.next()->ascii() +QString(">=")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xd://ptgGREAT_THAN printf("token:ptgGREAT_THAN\r\n"); operands.first(); s1=operands.next()->ascii() +QString(">")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe://ptgNOT_EQUAL printf("token:ptgNOTequal\r\n"); operands.first(); s1=operands.next()->ascii() +QString("!=")+operands.first()->ascii(); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x19://attribute can be Sum,If,Choose w3=Integer2Byte(data[idx],data[idx+1]);idx=idx+2; idx++; printf("token:ATTRIBUTE:0x%x\r\n",w3); for(w4=idx;w4<length;w4++) printf("0x%x, ",data[w4]); if(w3&0x01)//choose { printf("token:CHOOSE\r\n"); } else if(w3&0x02)//if { printf("token:IF\r\n"); } else if(w3&0x10)//sum { printf("token:SUM\r\n"); }; break; case 0x21: case 0x22: case 0x42: case 0x62: case 0x41: case 0x61://ptgFunction printf("token:ptgFunction\r\n"); if(token==0x22||token==0x42||token==0x62) { w2=(int)data[idx];idx++; w1=Integer2Byte(data[idx],data[idx+1]);idx=idx+2; } else { w1=Integer2Byte(data[idx],data[idx+1]);idx=idx+2; }; switch(w1) { case 0xf://SIN s1=QString("SIN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x10://COS s1=QString("COS(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x11://tan s1=QString("TAN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x62://asin s1=QString("ASIN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x63://ACOS s1=QString("ACOS(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x12://ATAN s1=QString("ATAN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe5://SINH s1=QString("SINH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe6://COSH s1=QString("COSH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe7://TANH s1=QString("TANH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe8://ASINH s1=QString("ASINH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xe9://ACOSH s1=QString("ACOSH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xea://ATANH s1=QString("ATANH(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x13://pi s1="PI()"; operands.prepend(new QString(s1)); break; case 0x14://sqrt s1=QString("SQRT(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x15://exp s1=QString("EXP(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x16://LN s1=QString("LN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x17://LOG10 s1=QString("LOG10(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x18://ABS s1=QString("ABS(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x19://int s1=QString("INT(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x1a://sign s1=QString("SIGN(")+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x1b://round operands.first(); s1=QString("ROUND(")+operands.next()->ascii() +QString(",")+operands.first()->ascii() +QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x1d://index operands.first(); s1=QString("INDEX(")+operands.next()->ascii() +QString(",") +operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x1: // if ATTRIBUTE operands.first();operands.next(); s1=QString("IF(")+operands.next()->ascii()+QString(","); operands.first(); s1=s1+operands.next()->ascii()+QString(","); s1=s1+operands.first()->ascii()+QString(")"); operands.removeFirst(); operands.removeFirst(); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x81://isblank s1=QString("ISBLANK(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x80://isnumber s1=QString("ISNUMBER(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x120://ceiling operands.first(); s1=QString("CEILING(")+operands.next()->ascii() +QString(",")+operands.first()->ascii() +QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x11d://floor operands.first(); s1=QString("FLOOR(")+operands.next()->ascii() +QString(",")+operands.first()->ascii() +QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x157://degrees s1=QString("DEGREES(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x156://radians s1=QString("RADIANS(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xb8://fact s1=QString("FACT(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x27://MOD operands.first(); s1=QString("MOD(")+operands.next()->ascii() +QString(",")+operands.first()->ascii() +QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x151://power operands.first(); s1=QString("POWER(")+operands.next()->ascii() +QString(",")+operands.first()->ascii() +QString(")"); operands.removeFirst();operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x3f://rand() s1="RAND()"; operands.prepend(new QString(s1)); break; case 0x4://sum for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("SUM(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x6://min for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("MIN(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x7://max for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("MAX(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x5://average for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("AVERAGE(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x2e://var for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("VAR(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xc2://varp for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("VARP(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xc://stdev for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("STDEV(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0xc1://stdevp for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("STDEVP(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x143://skew for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("SKEW(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x142://kurt for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("KURT(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; case 0x0://count for(w4=1;w4<w2;w4++) operands.removeFirst(); s1=QString("COUNT(")+operands.first()->ascii() +QString(")"); operands.removeFirst(); operands.prepend(new QString(s1)); break; default: printf("token:FUNCTION_UNKNOWN=0x%x\r\n",w1); return QString("FUNC_UNKNOWN"); break; }; break; default: printf("tokenUNKNOWN=0x%x\r\n",token); return QString("TOKEN_UKNOWN"); //it is dangerous to go to idx++ and not return // because the result is unexpected. // but there is a possibility the the parser will give the correct // answer, because there are some tokens in excel formulas that can be //ignored. idx++; break; }; }; printf("{////FormulaParser}\r\n"); printf("GetFormula:::::::r=%d,c=%d,,,%s\r\n",row,col,s1.ascii()); printf("\r\n"); s1=operands.first()->ascii(); operands.clear(); return QString(s1); }; QString ExcelBook::FindCellName(int row, int col) { row++;col++; QString s1=""; int i1=col % 26; int i2=col / 26; if (i2!=0) s1=(char)(i2+65); //65 =A s1=s1+(char)(i1+65-1); return (s1+QString::number(row)); }; diff --git a/noncore/apps/zsafe/zsafe.cpp b/noncore/apps/zsafe/zsafe.cpp index f70f863..9c0c6ce 100644 --- a/noncore/apps/zsafe/zsafe.cpp +++ b/noncore/apps/zsafe/zsafe.cpp @@ -1,3221 +1,3222 @@ /**************************************************************************** ** ** Created: Sat Apr 6 17:57:45 2002 ** ** Author: Carsten Schneider <CarstenSchneider@t-online.de> ** ** $Id$ ** ** Homepage: http://home.t-online.de/home/CarstenSchneider/zsafe/index.html ** ** ****************************************************************************/ #include "zsafe.h" #include "newdialog.h" #include "searchdialog.h" #include "categorydialog.h" #include "passworddialog.h" #include "infoform.h" #include "zlistview.h" #include "shadedlistitem.h" #include <opie2/oresource.h> #include <opie2/ofiledialog.h> #include <opie2/odebug.h> using namespace Opie::Core; using namespace Opie::Ui; #include <qclipboard.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <qmenubar.h> #include <qpopupmenu.h> #include <qfile.h> #include <qpe/applnk.h> #include <qpe/global.h> #include <qpe/qpeapplication.h> #include <qpe/config.h> #include <qaction.h> #include <qtimer.h> #include <qlayout.h> #include <qmessagebox.h> #include <qfile.h> #include <qtextstream.h> #include <qheader.h> #include <qlistview.h> #include <qvariant.h> #include <qtooltip.h> #include <qwhatsthis.h> #include <qimage.h> #include <qpixmap.h> #include <qlineedit.h> #include <qmultilineedit.h> #include <qregexp.h> #include <qdir.h> #include <qtextbrowser.h> #include <qlabel.h> #include <qcombobox.h> #include <qtoolbar.h> #include "krc2.h" #include "wait.h" const QString APP_KEY = ""; // include xmp images #include "pics/zsafe/expand.xpm" #include "pics/zsafe/export.xpm" #include "pics/zsafe/import.xpm" static const char* const bank_cards_data[] = { "14 14 16 1", ". c None", "# c #000000", "b c #0000de", "a c #0000e6", "j c #41de83", "k c #4acecd", "h c #4aced5", "g c #5a40cd", "d c #5a44d5", "l c #9440d5", "m c #b4ce4a", "n c #cd4883", "e c #d5ae10", "f c #de3ce6", "i c #e640e6", "c c #ffffff", "..............", ".###########..", ".#ababababa#..", ".#babbbabbb#..", ".#ccccccccc#..", ".#cdcefcghc#..", ".#ccccccccc#..", ".#cicjkclic#..", ".#ccccccccc#..", ".#cmchlcnec#..", ".#ccccccccc#..", ".###########..", "..............", ".............."}; static const char* const passwords_data[] = { "16 16 20 1", ". c None", "# c #000000", "r c #000083", "p c #0000c5", "q c #0000ff", "n c #008100", "l c #00c200", "m c #00ff00", "j c #838100", "a c #c55900", "h c #c5c200", "o c #c5c2ff", "k c #c5ffc5", "f c #ff0000", "d c #ff8100", "b c #ffaa5a", "e c #ffc2c5", "c c #ffdeac", "i c #ffff00", "g c #ffffc5", "............###.", "...........#abb#", "..........#cbab#", ".........#cbdd#.", "######..#cbdd#..", "#eeff#..#add#...", "#eeff#######....", "#ccdbdd#........", "#dddbdd###......", "#gghihhjj#......", "#hhhihhjj###....", "#kklmllnnnn#....", "#lllmllnnnn#....", "#oopqpprprr#....", "#oopqpprprr#....", "############...."}; static const char* const software_data[] = { "16 16 5 1", ". c None", "# c #000000", "b c #838183", "c c #c5ffff", "a c #ffffff", "................", ".##############.", "#aaaaaaaaaaaaaa#", "#abbbbbbbbbbbbb#", "#ab##########ab#", "#ab#c########ab#", "#ab#c#c######ab#", "#ab##########ab#", "#ab##########ab#", "#ab##########ab#", "#ab##########ab#", "#ab##########ab#", "#aaaaaaaaaaaaab#", "#bbbbbbbbbbbbbb#", ".##############.", "................"}; static const char* const general_data[] = { "14 14 98 2", "Qt c None", ".k c #000000", "#x c #080808", "#F c #101008", "#q c #101010", "#i c #101410", "## c #101810", ".m c #181818", ".3 c #181c18", ".I c #182018", ".T c #202420", "#D c #202820", "#y c #292c29", ".c c #293029", ".d c #313031", "#E c #313429", "#r c #313831", ".j c #393c31", "#j c #394039", "#C c #414841", ".w c #4a554a", ".a c #4a594a", ".# c #525052", ".l c #52594a", "#f c #525952", "#v c #525d52", ".O c #5a4c4a", ".9 c #5a595a", ".A c #5a5d52", ".B c #624c52", ".0 c #625552", "#o c #626562", ".R c #626962", "#. c #626d5a", "#p c #626d62", ".2 c #627162", "#h c #6a6d62", "#z c #6a7562", "#w c #6a756a", ".C c #73656a", ".P c #73696a", "#a c #737d6a", ".U c #738573", ".E c #7b817b", "#B c #7b857b", "#s c #7b897b", "#n c #7b917b", ".b c #838d83", ".7 c #839583", ".n c #8b7d7b", "#g c #8b8583", ".g c #8b858b", ".r c #8b898b", ".s c #8b8d8b", ".i c #8b9183", ".8 c #8b918b", "#A c #8b9d8b", ".S c #8ba183", ".Z c #94918b", ".N c #949994", ".F c #949d94", ".x c #94a18b", ".v c #94a194", ".Y c #94aa94", ".h c #9c999c", ".Q c #9ca19c", "#u c #9ca59c", ".H c #9caa9c", "#e c #9cb29c", "#m c #a4b29c", "#t c #a4b2a4", ".M c #a4b69c", "#l c #a4b6a4", ".z c #a4baa4", ".f c #aca5ac", ".q c #acaaac", "#d c #acbeac", ".6 c #acc2ac", ".o c #b4b2b4", ".t c #b4beb4", "#k c #b4c2ac", ".5 c #b4cab4", ".D c #bdb6bd", ".G c #bdc6b4", "#c c #bdceb4", ".X c #bdd2bd", ".4 c #bdd6bd", ".1 c #c5bec5", ".e c #c5c2c5", ".u c #c5cac5", "#b c #c5d6c5", ".J c #c5dec5", ".p c #cdcacd", ".W c #cddecd", ".L c #cde2cd", ".K c #d5eacd", ".V c #d5ead5", ".y c #d5eed5", "QtQtQtQtQtQtQtQtQtQtQtQtQtQt", "QtQtQt.#.a.b.cQtQtQtQtQtQtQt", "QtQt.d.e.f.g.h.i.c.j.dQt.kQt", ".a.l.m.n.o.p.q.r.s.t.u.v.wQt", ".x.y.z.A.B.C.D.p.q.E.F.G.H.I", ".I.J.K.L.M.N.O.P.o.p.Q.R.S.T", "Qt.U.V.L.W.X.Y.Z.0.P.1.s.2.3", "Qt.3.X.W.4.X.5.6.7.8.9.s#.##", "QtQt#a.X#b#c.5.6#d#e#f#g#h#i", "QtQtQt#j.7#k.6#d#l#m#n#o#p#q", "QtQtQtQt.k#r#s#m#t.H#u#v#w#x", "QtQtQtQtQtQt.k#y#z.v#A#B#C#x", "QtQtQtQtQtQtQtQt.k#D.w#s#E.k", "QtQtQtQtQtQtQtQtQtQtQt#x#FQt"}; // exit ZSafe and clear the clipboard for security reasons void ZSafe::exitZs (int ec) { QClipboard *cb = QApplication::clipboard(); cb->clear(); exit (ec); } // save the configuration into the file void ZSafe::saveConf () { if (conf) { delete conf; conf = new Config ("zsafe"); conf->setGroup ("zsafe"); } } /* * Constructs a ZSafe which is a child of 'parent', with the * name 'name' and widget flags set to 'f' * * The dialog will by default be modeless, unless you set 'modal' to * TRUE to construct a modal dialog. */ ZSafe::ZSafe( QWidget* parent, const char* name, WFlags fl ) : QMainWindow( parent, name, fl), ListView(0l) { IsCut = false; IsCopy = false; modified = false; showpwd = false; // set the config file cfgFile=QDir::homeDirPath(); cfgFile += "/.zsafe.cfg"; // set the icon path QString qpeDir = QPEApplication::qpeDir(); conf = new Config ("zsafe"); conf->setGroup ("zsafePrefs"); expandTree = conf->readNumEntry(APP_KEY+"expandTree", 0); conf->setGroup ("zsafe"); QPixmap new_img = Opie::Core::OResource::loadPixmap( "new", Opie::Core::OResource::SmallIcon ); QPixmap edit_img = Opie::Core::OResource::loadPixmap( "edit", Opie::Core::OResource::SmallIcon ); QPixmap trash_img = Opie::Core::OResource::loadPixmap( "trash", Opie::Core::OResource::SmallIcon ); QPixmap copy_img = Opie::Core::OResource::loadPixmap( "copy", Opie::Core::OResource::SmallIcon ); QPixmap cut_img = Opie::Core::OResource::loadPixmap( "cut", Opie::Core::OResource::SmallIcon ); QPixmap editdelete_img = Opie::Core::OResource::loadPixmap( "editdelete", Opie::Core::OResource::SmallIcon ); QPixmap folder_open_img = Opie::Core::OResource::loadPixmap( "folder_open", Opie::Core::OResource::SmallIcon ); QPixmap help_icon_img = Opie::Core::OResource::loadPixmap( "help_icon", Opie::Core::OResource::SmallIcon ); QPixmap paste_img = Opie::Core::OResource::loadPixmap( "paste", Opie::Core::OResource::SmallIcon ); QPixmap save_img = Opie::Core::OResource::loadPixmap( "save", Opie::Core::OResource::SmallIcon ); QPixmap expand_img((const char**) expand_xpm); QPixmap export_img((const char**) export_xpm); QPixmap import_img((const char**) import_xpm); QPixmap bank_cards( ( const char** ) bank_cards_data ); QPixmap passwords( ( const char** ) passwords_data ); QPixmap software( ( const char** ) software_data ); QPixmap general( ( const char** ) general_data ); QPixmap image0 = Opie::Core::OResource::loadPixmap( "zsafe/zsafe", Opie::Core::OResource::SmallIcon ); if ( !name ) setName( "ZSafe" ); setCaption( tr( "ZSafe" ) ); QString zsafeAppDirPath = QDir::homeDirPath() + "/Documents/application/zsafe"; filename = conf->readEntry(APP_KEY+"document"); if ( !QFileInfo(filename).exists() || !QDir(zsafeAppDirPath).exists() ) { // check if the directory application exists, if not // create it QString d1(QDir::homeDirPath() + "/Documents/application"); QDir pd1(d1); if (!pd1.exists()) { QDir pd2(QDir::homeDirPath() + "/Documents"); if (!pd2.exists()) { QDir pd3(QDir::homeDirPath()); if (!pd3.mkdir("Documents", FALSE)) { } } if (!pd2.mkdir("application", FALSE)) { QMessageBox::critical( 0, tr("ZSafe"), tr("<P>Can't create directory %1</P><P>ZSafe will now exit.</P>").arg(d1)); exitZs (1); } } QString d2(QDir::homeDirPath() + "/Documents/application/zsafe"); QDir pd2(d2); if (!pd2.exists()) { if (!pd1.mkdir("zsafe", FALSE)) { QMessageBox::critical( 0, tr("ZSafe"), tr("<P>Can't create directory %1</P><P>ZSafe will now exit.</P>").arg(d2)); exitZs (1); } } filename = zsafeAppDirPath + "/passwords.zsf"; // save the current filename to the config file conf->writeEntry(APP_KEY+"document", filename); saveConf(); } //if (filename == "INVALIDPWD") //filename = ""; QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); this->setCaption(tr("ZSafe: ") + ti); selectedItem = NULL; lastSearchedCategory = NULL; lastSearchedItem = NULL; lastSearchedName = ""; lastSearchedUsername = ""; lastSearchedComment = ""; infoForm = new InfoForm(this, "show_info", TRUE); categoryDialog = NULL; infoForm->setIcon( image0); // Create menu and tool bar dock setToolBarsMovable( false ); QToolBar *dock = new QToolBar( this ); dock->setHorizontalStretchable( true ); // add a menu bar QMenuBar *menu = new QMenuBar( dock ); menu->setMargin( 0 ); // Add a toolbar QToolBar *toolbar = new QToolBar( this ); // add file menu // QPopupMenu *file = new QPopupMenu( this ); file = new QPopupMenu( this ); // File menu file->insertItem( new_img, tr("New document"), this, SLOT(newDocument()) ); file->insertItem( folder_open_img, tr("Open document"), this, SLOT(loadDocument()) ); file->insertItem( save_img, tr("Save document as"), this, SLOT(saveDocumentAs()) ); file->insertSeparator(); file->insertItem( save_img, tr("Save document"), this, SLOT(saveDocumentWithoutPwd()) ); file->insertItem( save_img, tr("Save document with new Password"), this, SLOT(saveDocumentWithPwd()) ); file->insertSeparator(); file->insertItem( export_img, tr("Export text file"), this, SLOT(writeAllEntries()) ); file->insertItem( import_img, tr("Import text file"), this, SLOT(readAllEntries()) ); file->insertItem( trash_img, tr("Remove text file"), this, SLOT(removeAsciiFile()) ); file->insertSeparator(); file->insertItem( expand_img, tr("Open entries expanded"), this, SLOT(setExpandFlag()), 0, 'o'); file->setItemChecked('o', expandTree); menu->insertItem( tr("File"), file ); // Category menu QPopupMenu *cat = new QPopupMenu( this ); cat->insertItem( new_img, tr("New"), this, SLOT(addCategory()) ); cat->insertItem( edit_img, tr("Edit"), this, SLOT(editCategory()) ); cat->insertItem( trash_img, tr("Delete"), this, SLOT(delCategory()) ); menu->insertItem( tr("Category"), cat ); // Entry menu QPopupMenu *it = new QPopupMenu( this ); it->insertItem( cut_img, tr("Cut"), this, SLOT(cutItem()) ); it->insertItem( copy_img, tr("Copy"), this, SLOT(copyItem()) ); it->insertItem( paste_img, tr("Paste"), this, SLOT(pasteItem()) ); it->insertSeparator(); QAction *a = new QAction( tr( "New" ), new_img, QString::null, 0, this, 0 ); connect( a, SIGNAL(activated()), this, SLOT(newPwd()) ); a->addTo( it ); a->addTo( toolbar ); a = new QAction( tr( "Edit" ), edit_img, QString::null, 0, this, 0 ); connect( a, SIGNAL(activated()), this, SLOT(editPwd()) ); a->addTo( it ); a->addTo( toolbar ); a = new QAction( tr( "Delete" ), trash_img, QString::null, 0, this, 0 ); connect( a, SIGNAL(activated()), this, SLOT(deletePwd()) ); a->addTo( it ); a->addTo( toolbar ); a = new QAction( tr( "Search" ), Opie::Core::OResource::loadPixmap( "find", Opie::Core::OResource::SmallIcon ), QString::null, 0, this, 0 ); connect( a, SIGNAL(activated()), this, SLOT(findPwd()) ); a->addTo( it ); a->addTo( toolbar ); menu->insertItem( tr("Entry"), it ); // Add main view ListView = new ZListView( this, "ListView" ); ListView->addColumn( tr( "Name" ) ); ListView->addColumn( tr( "Field 2" ) ); ListView->addColumn( tr( "Field 3" ) ); ListView->addColumn( tr( "Comment" ) ); ListView->addColumn( tr( "Field 4" ) ); ListView->addColumn( tr( "Field 5" ) ); ListView->setAllColumnsShowFocus(TRUE); ListView->setResizePolicy(QScrollView::AutoOneFit); setCentralWidget( ListView ); QBoxLayout * l = new QVBoxLayout( this ); l->addWidget (menu); l->addWidget (ListView); // start a timer (100 ms) to load the default document docuTimer.start( 100, true ); connect( &docuTimer, SIGNAL(timeout()), SLOT( slotLoadDocu() ) ); raiseFlag = true; connect( &raiseTimer, SIGNAL(timeout()), SLOT( slotRaiseTimer() ) ); // signals and slots connections for QListView connect( ListView, SIGNAL( selectionChanged(QListViewItem*) ), this, SLOT( listViewSelected(QListViewItem*) ) ); connect( ListView, SIGNAL( doubleClicked(QListViewItem*) ), this, SLOT( showInfo(QListViewItem*) ) ); connect( ListView, SIGNAL( returnPressed(QListViewItem*) ), this, SLOT( showInfo(QListViewItem*) ) ); QPEApplication::setStylusOperation( ListView->viewport(),QPEApplication::RightOnHold); connect( ListView, SIGNAL( mouseButtonPressed( int, QListViewItem *, const QPoint&, int)), this,SLOT( ListPressed(int, QListViewItem *, const QPoint&, int)) ); this->setIcon( image0); } const QColor *ZSafe::evenRowColor = &Qt::white; // const QColor *ZSafe::oddRowColor = &Qt::lightGray; const QColor *ZSafe::oddRowColor = new QColor(216,240,255); /* * Destroys the object and frees any allocated resources */ ZSafe::~ZSafe() { // no need to delete child widgets, Qt does it all for us quitMe(); } // load the default document void ZSafe::slotLoadDocu() { openDocument (filename); } void ZSafe::deletePwd() { if (!selectedItem) return; if (!isCategory(selectedItem)) { switch( QMessageBox::information( this, tr("ZSafe"), tr("Do you want to delete?"), tr("&Delete"), tr("D&on't Delete"), 0 // Enter == button 0 ) ) { // Escape == button 2 case 0: // Delete clicked, Alt-S or Enter pressed. // Delete modified = true; selectedItem->parent()->takeItem(selectedItem); selectedItem = NULL; break; case 1: // Don't delete break; } } else { delCategory(); } } void ZSafe::editPwd() { if (!selectedItem) return; if (!isCategory(selectedItem)) { // open the 'New Entry' dialog NewDialog *dialog = new NewDialog(this, "edit_entry", TRUE); // set the labels dialog->Name->setText(getFieldLabel (selectedItem, "1", tr("Name"))); dialog->Username->setText(getFieldLabel (selectedItem, "2", tr("Username"))); dialog->Password->setText(getFieldLabel (selectedItem, "3", tr("Password"))); dialog->Comment->setText(getFieldLabel (selectedItem, "4", tr("Comment"))); dialog->Field5Label->setText(getFieldLabel (selectedItem,"5", tr("Field 4"))); dialog->Field6Label->setText(getFieldLabel (selectedItem,"6", tr("Field 5"))); // set the fields dialog->NameField->setText(selectedItem->text (0)); dialog->UsernameField->setText(selectedItem->text (1)); dialog->PasswordField->setText(selectedItem->text (2)); QString comment = selectedItem->text (3); comment.replace (QRegExp("<br>"), "\n"); dialog->Field5->setText(selectedItem->text (4)); dialog->Field6->setText(selectedItem->text (5)); dialog->CommentField->insertLine(comment); dialog->CommentField->setCursorPosition(0,0); QDialog::DialogCode result = (QDialog::DialogCode) QPEApplication::execDialog( dialog ); if (result == QDialog::Accepted) { modified = true; // edit the selected item QString name = dialog->NameField->text(); selectedItem->setText (0, tr (name)); QString user = dialog->UsernameField->text(); selectedItem->setText (1, tr (user)); QString pwd = dialog->PasswordField->text(); selectedItem->setText (2, tr (pwd)); QString comment = dialog->CommentField->text(); comment.replace (QRegExp("\n"), "<br>"); selectedItem->setText (3, tr (comment)); QString f5 = dialog->Field5->text(); selectedItem->setText (4, tr (f5)); QString f6 = dialog->Field6->text(); selectedItem->setText (5, tr (f6)); } delete dialog; } else { editCategory(); } } void ZSafe::newPwd() { if (!selectedItem) return; qWarning("new item"); if (!isCategory(selectedItem)) selectedItem = selectedItem->parent(); if (isCategory(selectedItem)) { QString cat = selectedItem->text(0); qWarning(cat); // open the 'New Entry' dialog NewDialog *dialog = new NewDialog(this, "new_entry", TRUE); // set the labels dialog->Name->setText(getFieldLabel (selectedItem, "1", tr("Name"))); dialog->Username->setText(getFieldLabel (selectedItem, "2", tr("Username"))); dialog->Password->setText(getFieldLabel (selectedItem, "3", tr("Password"))); dialog->Comment->setText(getFieldLabel (selectedItem, "4", tr("Comment"))); dialog->Field5Label->setText(getFieldLabel (selectedItem,"5", tr("Field 4"))); dialog->Field6Label->setText(getFieldLabel (selectedItem,"6", tr("Field 5"))); retype: #ifdef Q_WS_QWS QDialog::DialogCode result = (QDialog::DialogCode) QPEApplication::execDialog( dialog ); #endif if (result == QDialog::Accepted) { QString name = dialog->NameField->text(); if (cat == name) { QMessageBox::critical( 0, tr("ZSafe"), tr("Entry name must be different\nfrom the category name.") ); goto retype; // it's not a good programming style :-) } modified = true; // add the new item QListViewItem *i = new ShadedListItem (0, selectedItem); i->setOpen (TRUE); i->setText (0, tr (name)); QString user = dialog->UsernameField->text(); i->setText (1, tr (user)); QString pwd = dialog->PasswordField->text(); i->setText (2, tr (pwd)); QString comment = dialog->CommentField->text(); comment.replace (QRegExp("\n"), "<br>"); i->setText (3, tr (comment)); QString f5 = dialog->Field5->text(); i->setText (4, tr (f5)); QString f6 = dialog->Field6->text(); i->setText (5, tr (f6)); } delete dialog; } } void ZSafe::findPwd() { // open the 'Search' dialog SearchDialog *dialog = new SearchDialog(this, tr("Search"), TRUE); if (lastSearchedName) dialog->NameField->setText(lastSearchedName); else dialog->NameField->setText(""); if (lastSearchedUsername) dialog->UsernameField->setText(lastSearchedUsername); else dialog->UsernameField->setText(""); if (lastSearchedComment) dialog->CommentField->setText(lastSearchedComment); else dialog->CommentField->setText(""); QDialog::DialogCode result = (QDialog::DialogCode) dialog->exec(); QString name; QString username; QString comment; if (result == QDialog::Accepted) { name = dialog->NameField->text(); username = dialog->UsernameField->text(); comment = dialog->CommentField->text(); } else { delete dialog; return; } if (!name.isEmpty() && name != lastSearchedName || lastSearchedName.isEmpty() && !name.isEmpty()) { // set search at the beginning if a new name is given lastSearchedCategory = NULL; lastSearchedItem = NULL; } lastSearchedName = name; if (!username.isEmpty() && username != lastSearchedUsername || lastSearchedUsername.isEmpty() && !username.isEmpty()) { // set search at the beginning if a new name is given lastSearchedCategory = NULL; lastSearchedItem = NULL; } lastSearchedUsername = username; if (!comment.isEmpty() && comment != lastSearchedComment || lastSearchedComment.isEmpty() && !comment.isEmpty()) { // set search at the beginning if a new name is given lastSearchedCategory = NULL; lastSearchedItem = NULL; } lastSearchedComment = comment; ListView->clearSelection(); bool found=FALSE; // step through all categories QListViewItem *i; if (lastSearchedCategory) i = lastSearchedCategory; else i = ListView->firstChild(); for (; i != NULL; i = i->nextSibling()) { i->setSelected(FALSE); // step through all subitems QListViewItem *si; if (lastSearchedItem) si = lastSearchedItem; else si = i->firstChild(); // for (si = i->firstChild(); for (; si != NULL; si = si->nextSibling()) { if (si->isSelected()) si->setSelected(FALSE); // ListView->repaintItem(si); bool n=TRUE; bool u=TRUE; bool c=TRUE; if (!name.isEmpty()) n = (si->text(0)).contains (name, FALSE); if (!username.isEmpty()) u = (si->text(1)).contains (username, FALSE); if (!comment.isEmpty()) c = (si->text(3)).contains (comment, FALSE); if ((n && u && c ) && !found) { selectedItem = si; si->setSelected(TRUE); ListView->setCurrentItem(si); ListView->ensureItemVisible(si); ListView->triggerUpdate(); lastSearchedCategory = i; // set to the next item lastSearchedItem = si->nextSibling(); if (!lastSearchedItem) { // no next item within category -> set next category lastSearchedCategory = i->nextSibling(); if (!lastSearchedCategory) lastSearchedItem = NULL; // END } found = TRUE; delete dialog; update(); return; } } lastSearchedCategory = i->nextSibling(); lastSearchedItem = NULL; } lastSearchedCategory = NULL; lastSearchedItem = NULL; delete dialog; update(); QMessageBox::information( this, tr("ZSafe"), tr("Entry not found"), tr("&OK"), 0); } QString ZSafe::getFieldLabel (QListViewItem *_item, QString field, QString def) { QString category; if (_item) { if (isCategory(_item)) { category = _item->text(0); } else { QListViewItem *cat = _item->parent(); category = cat->text(0); } } else { return def; } QString app_key = APP_KEY; conf->setGroup( "fieldDefs" ); QString label = conf->readEntry(app_key+category+"-field"+field,def); conf->setGroup ("zsafe"); return label; } QString ZSafe::getFieldLabel (QString category, QString field, QString def) { QString app_key = APP_KEY; // #ifndef Q_WS_WIN conf->setGroup( "fieldDefs" ); QString label = conf->readEntry(app_key+category+"-field"+field, def); // #else // QString label(def); // #endif conf->setGroup ("zsafe"); return label; } void ZSafe::showInfo( QListViewItem *_item) { if (!_item) return; if (selectedItem != NULL) selectedItem->setSelected(FALSE); selectedItem = _item; selectedItem->setSelected(TRUE); if (!isCategory(_item)) { /* QString label=selectedItem->text(0); label+="\n"; label+=selectedItem->text(1); label+="\n"; label+=selectedItem->text(2); label+="\n"; label+=selectedItem->text(3); */ QString text; QString entry; text = "<html><body><div align=""center""><u><b>"; text += selectedItem->text(0); text += "</b></u><br></div><br>"; entry = selectedItem->text(1); if (!entry.isEmpty() && entry.compare(" ")) { text += "<u><b>"; text += getFieldLabel (selectedItem, "2", tr("Username")); text += ":<br></b></u><blockquote>"; text += entry; text += "</blockquote>"; // text += "<br>"; } entry = selectedItem->text(2); if (!entry.isEmpty() && entry.compare(" ")) { text += "<u><b>"; text += getFieldLabel (selectedItem, "3", tr("Password")); text += ":<br> </b></u><blockquote>"; text += entry; text += "</blockquote>"; // text += "<br>"; } entry = selectedItem->text(4); if (!entry.isEmpty() && entry.compare(" ")) { text += "<u><b>"; text += getFieldLabel (selectedItem, "5", tr("Field 4")); text += ":<br> </b></u><blockquote>"; text += entry; text += "</blockquote>"; // text += "<br>"; } entry = selectedItem->text(5); if (!entry.isEmpty() && entry.compare(" ")) { text += "<u><b>"; text += getFieldLabel (selectedItem, "6", tr("Field 5")); text += ":<br> </b></u><blockquote>"; text += entry; text += "</blockquote>"; // text += "<br>"; } entry = selectedItem->text(3); if (!entry.isEmpty() && entry.compare(" ")) { text += "<u><b>"; text += getFieldLabel (selectedItem, "4", tr("Comment")); text += ":<br> </b></u>"; QString comment = selectedItem->text(3); comment.replace (QRegExp("\n"), "<br>"); text += comment; // text += "<br>"; } text += "</body></html>"; infoForm->InfoText->setText(text); // infoForm->hide(); #ifdef Q_WS_QWS QPEApplication::showDialog( infoForm ); #endif } } void ZSafe::listViewSelected( QListViewItem *_item) { if (!_item) return; if (selectedItem != NULL) selectedItem->setSelected(FALSE); selectedItem = _item; // set the column text dependent on the selected item ListView->setColumnText(0, getFieldLabel (selectedItem, "1", tr("Name"))); ListView->setColumnText(1, getFieldLabel (selectedItem, "2", tr("Field 2"))); ListView->setColumnText(2, getFieldLabel (selectedItem, "3", tr("Field 3"))); ListView->setColumnText(3, getFieldLabel (selectedItem, "4", tr("Comment"))); ListView->setColumnText(4, getFieldLabel (selectedItem, "5", tr("Field 4"))); ListView->setColumnText(5, getFieldLabel (selectedItem, "6", tr("Field 5"))); } bool ZSafe::isCategory(QListViewItem *_item) { if (_item == NULL) return FALSE; QString categoryName = _item->text (0); if (categories.find (categoryName)) return TRUE; else return FALSE; } void ZSafe::removeAsciiFile() { // QString fn = filename + ".txt"; // open the file dialog QMap<QString, QStringList> mimeTypes; mimeTypes.insert(tr("All"), QStringList() ); mimeTypes.insert(tr("Text"), "text/*" ); QString fn = OFileDialog::getOpenFileName( OFileSelector::EXTENDED_ALL, QDir::homeDirPath() + "/Documents/application/zsafe", QString::null, mimeTypes, this, tr ("Remove text file")); if (fn && fn.length() > 0 ) { QFile f( fn ); if ( !f.remove() ) { QMessageBox::critical( 0, tr("ZSafe"), tr("Could not remove text file.") ); return; } } } void ZSafe::writeAllEntries() { if (filename.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("No document defined.\nYou have to create a new document")); return; } // open the file dialog QString fn = zsaveDialog(); // open the new document if (fn && fn.length() > 0 ) { QFile f( fn ); if ( !f.open( IO_WriteOnly ) ) { QMessageBox::critical( 0, "ZSafe", QString("Could not export to text file.") ); return; } QTextStream t( &f ); QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; si = si->nextSibling()) { QString oneEntry; oneEntry += "\""; oneEntry += i->text(0); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(0); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(1); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(2); oneEntry += "\";"; oneEntry += "\""; QString comment = si->text(3); comment.replace (QRegExp("\n"), "<br>"); oneEntry += comment; oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(4); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(5); oneEntry += "\""; // owarn << oneEntry << oendl; t << oneEntry << endl; // owarn << si->text(0) << oendl; } } f.close(); } } void ZSafe::readAllEntries() { if (filename.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("No document defined.\nYou have to create a new document")); return; } // open the file dialog QMap<QString, QStringList> mimeTypes; mimeTypes.insert(tr("All"), QStringList() ); mimeTypes.insert(tr("Text"), "text/*" ); QString fn = OFileDialog::getOpenFileName( OFileSelector::EXTENDED_ALL, QDir::homeDirPath() + "/Documents/application/zsafe", QString::null, mimeTypes, this, tr ("Import text file")); if (fn && fn.length() > 0 ) { QFile f( fn ); if ( !f.open( IO_ReadOnly ) ) { QMessageBox::critical( 0, "ZSafe", QString("Could not import text file.") ); return; } modified = true; // clear the password list selectedItem = NULL; QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) // si = si->nextSibling()) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } QTextStream t(&f); while ( !t.eof() ) { QString s = t.readLine(); s.replace (QRegExp("\";\""), "\"|\""); // char buffer[1024]; char buffer[s.length()+1]; /* modify QString -> QCString::utf8 */ strcpy (buffer, s.utf8()); QString name; QString user; QString password; QString comment; QString field5=""; QString field6=""; // separete the entries char *i = strtok (buffer, "|"); QString category(QString::fromUtf8(&i[1])); category.truncate(category.length() -1); int idx=0; while ((i = strtok (NULL, "|")) != NULL) { switch (idx) { case 0: name = QString::fromUtf8(&i[1]); name.truncate(name.length() -1); // name break; case 1: // user user = QString::fromUtf8(&i[1]); user.truncate(user.length() -1); break; case 2: // password password = QString::fromUtf8(&i[1]); password.truncate(password.length() -1); break; case 3: // comment comment = QString::fromUtf8(&i[1]); comment.truncate(comment.length() -1); break; case 4: // field5 field5 = QString::fromUtf8(&i[1]); field5.truncate(field5.length() -1); break; case 5: // field6 field6 = QString::fromUtf8(&i[1]); field6.truncate(field6.length() -1); break; } idx++; } Category *cat= categories.find (category); if (cat) { // use the existend item QListViewItem *catItem = cat->getListItem(); if (catItem) { QListViewItem * item = new ShadedListItem( 0, catItem ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); item->setText( 4, tr( field5 ) ); item->setText( 5, tr( field6 ) ); catItem->setOpen( TRUE ); } } else { QListViewItem *catI = new ShadedListItem( 1, ListView ); // create and insert a new item QListViewItem * item = new ShadedListItem( 0, catI ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); item->setText( 4, tr( field5 ) ); item->setText( 5, tr( field6 ) ); catI->setOpen( TRUE ); Category *c1 = new Category(); c1->setCategoryName(category); QString icon; QString fullIconPath; QPixmap *pix; // #ifndef Q_WS_WIN icon = conf->readEntry(APP_KEY+category); // #endif bool isIconAv = false; if (!icon.isEmpty() && !icon.isNull()) { // build the full path fullIconPath = iconPath + icon; pix = new QPixmap (fullIconPath); if (!pix->isNull()) { QImage img = pix->convertToImage(); pix->convertFromImage(img.smoothScale(14,14)); c1->setIconName (icon); c1->setIcon (*pix); isIconAv = true; } } if (!isIconAv) { c1->setIcon (*getPredefinedIcon(category)); } c1->setListItem (catI); c1->initListItem(); categories.insert (c1->getCategoryName(), c1); } } f.close(); } else { } } #ifdef UNUSED void ZSafe::writeAllEntries() { if (filename.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("<P>No document defined. You have to create a new document</P>")); return; } // open the file for writing QString fn = filename + ".txt"; QFile f( fn ); if ( !f.open( IO_WriteOnly ) ) { QMessageBox::critical( 0, tr("ZSafe"), tr("Could not export to text file.") ); return; } QTextStream t( &f ); QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; si = si->nextSibling()) { QString oneEntry; oneEntry += "\""; oneEntry += i->text(0); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(0); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(1); oneEntry += "\";"; oneEntry += "\""; oneEntry += si->text(2); oneEntry += "\";"; oneEntry += "\""; // oneEntry += si->text(3); QString comment = si->text(3); comment.replace (QRegExp("\n"), "<br>"); oneEntry += comment; oneEntry += "\""; // owarn << oneEntry << oendl; t << oneEntry << endl; // owarn << si->text(0) << oendl; } } f.close(); } void ZSafe::readAllEntries() { QString fn = filename + ".txt"; QFile f( fn ); if ( !f.open( IO_ReadOnly ) ) { QMessageBox::critical( 0, tr("ZSafe"), tr("Could not import text file.") ); return; } modified = true; // clear the password list selectedItem = NULL; QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) // si = si->nextSibling()) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } QTextStream t(&f); while ( !t.eof() ) { QString s = t.readLine(); s.replace (QRegExp("\";\""), "\"|\""); // char buffer[1024]; int len=s.length()+1; char buffer[len]; strcpy (buffer, s); QString name; QString user; QString password; QString comment; // separete the entries char *i = strtok (buffer, "|"); QString category(&i[1]); category.truncate(category.length() -1); int idx=0; while (i = strtok (NULL, "|")) { switch (idx) { case 0: name = &i[1]; name.truncate(name.length() -1); // name break; case 1: // user user = &i[1]; user.truncate(user.length() -1); break; case 2: // password password = &i[1]; password.truncate(password.length() -1); break; case 3: // comment comment = &i[1]; comment.truncate(comment.length() -1); break; } idx++; } Category *cat= categories.find (category); if (cat) { // use the existend item QListViewItem *catItem = cat->getListItem(); if (catItem) { QListViewItem * item = new ShadedListItem( 0, catItem ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); catItem->setOpen( TRUE ); } } else { QListViewItem *catI = new ShadedListItem( 1, ListView ); // create and insert a new item QListViewItem * item = new ShadedListItem( 0, catI ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); catI->setOpen( TRUE ); Category *c1 = new Category(); c1->setCategoryName(category); QString icon; QString fullIconPath; QPixmap *pix; // #ifndef Q_WS_WIN icon = conf->readEntry(APP_KEY+category); // #endif bool isIconAv = false; if (!icon.isEmpty() && !icon.isNull()) { // build the full path fullIconPath = iconPath + icon; pix = new QPixmap (fullIconPath); if (!pix->isNull()) { QImage img = pix->convertToImage(); pix->convertFromImage(img.smoothScale(14,14)); c1->setIconName (icon); c1->setIcon (*pix); isIconAv = true; } } if (!isIconAv) { c1->setIcon (*getPredefinedIcon(category)); } c1->setListItem (catI); c1->initListItem(); categories.insert (c1->getCategoryName(), c1); } } f.close(); } #endif // UNUSED void ZSafe::resume(int) { // hide the main window if ( !showpwd ) { infoForm->hide(); // open zsafe again m_password = ""; selectedItem = NULL; // clear the password list QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } // ask for password and read again openDocument(filename); } } //--------------------------------------------- bool ZSafe::openDocument(const char* _filename, const char* ) { QString name= _filename; qWarning("openDocument "+name); int retval; char* entry[FIELD_SIZE]; // #ifndef Q_WS_WIN int validationFlag = conf->readNumEntry(APP_KEY+"valzsafe", 1); // #else // int validationFlag = 1; // #endif int pwdOk = 0; int numberOfTries = 3; for (int i=0; i < numberOfTries; i++) { QFile f(_filename); if (f.exists()) { // ask with a dialog for the password if (m_password.isEmpty()) getDocPassword(tr("Enter Password")); if (m_password.isEmpty() && validationFlag == 0) { QMessageBox::critical( 0, tr("ZSafe"), tr("Wrong password.\n\nZSafe will now exit.") ); exitZs (1); } retval = loadInit(_filename, m_password); if (retval != PWERR_GOOD) { return false; } } else { this->setCaption(tr("ZSafe")); filename = ""; switch( QMessageBox::warning( this, tr("ZSafe"), tr("<P>You must create a new document first. Ok to create?</P>"), tr("&Yes"), tr("&No."), 0 ) ) { case 1: // No return false; break; case 0: // Yes newDocument(); return false; break; } } // load the validation entry if (validationFlag == 0) { pwdOk = 1; break; } retval = loadEntry(entry); if (retval == 1 && !strcmp (entry[0], "ZSAFECATEGORY") && !strcmp (entry[1], "name") && !strcmp (entry[2], "username") && !strcmp (entry[3], "password") && !strcmp (entry[4], "comment") ) { for (int count = 0; count < FIELD_SIZE; count++) free(entry[count]); pwdOk = 1; break; } else // for (int count = 0; count < FIELD_SIZE; count++) free(entry[count]); fclose (fd); m_password = ""; if (i < numberOfTries - 1) { switch( QMessageBox::warning( this, tr("ZSafe"), tr("Wrong password.\nEnter again?"), tr("&Yes"), tr("&No."), 0 ) ) { case 1: // No exitZs (1); break; case 0: // Yes continue; } } } if (pwdOk == 0) { // unset the document entry conf->writeEntry(APP_KEY+"document", "INVALIDPWD"); if (conf) delete conf; exitZs (1); } retval = loadEntry(entry); int numberOfEntries=0; while (retval == 1) { QString category( QString::fromUtf8(entry[0]) ); QString name( QString::fromUtf8(entry[1]) ); QString user( QString::fromUtf8(entry[2]) ); QString password( QString::fromUtf8(entry[3]) ); QString comment( QString::fromUtf8(entry[4]) ); QString field5( QString::fromUtf8(entry[5]) ); QString field6( QString::fromUtf8(entry[6]) ); // add the subitems to the categories Category *cat= categories.find (category); if (cat) { // use the existend item QListViewItem *catItem = cat->getListItem(); if (catItem) { QListViewItem * item = new ShadedListItem( 0, catItem ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); item->setText( 4, tr( field5 ) ); item->setText( 5, tr( field6 ) ); if (expandTree) catItem->setOpen( TRUE ); numberOfEntries++; } } else { QListViewItem *catI = new ShadedListItem( 1, ListView ); // create and insert a new item QListViewItem * item = new ShadedListItem( 0, catI ); item->setText( 0, tr( name ) ); item->setText( 1, tr( user ) ); item->setText( 2, tr( password ) ); item->setText( 3, tr( comment ) ); item->setText( 4, tr( field5 ) ); item->setText( 5, tr( field6 ) ); if (expandTree) catI->setOpen( TRUE ); Category *c1 = new Category(); c1->setCategoryName(category); QString icon; QString fullIconPath; QPixmap *pix; // #ifndef Q_WS_WIN icon = conf->readEntry(APP_KEY+category); // #endif bool isIconAv = false; if (!icon.isEmpty() && !icon.isNull()) { // build the full path fullIconPath = iconPath + icon; pix = new QPixmap (fullIconPath); if (!pix->isNull()) { QImage img = pix->convertToImage(); pix->convertFromImage(img.smoothScale(14,14)); c1->setIconName (icon); c1->setIcon (*pix); isIconAv = true; } } if (!isIconAv) { c1->setIcon (*getPredefinedIcon(category)); } c1->setListItem (catI); c1->initListItem(); categories.insert (c1->getCategoryName(), c1); numberOfEntries++; } for (int count = 0; count < FIELD_SIZE; count++) { free(entry[count]); } retval = loadEntry(entry); if (retval == 2) { // m_parent->slotStatusHelpMsg("Last entry loaded"); } } // end while if (numberOfEntries == 0) { switch( QMessageBox::warning( this, tr("ZSafe"), tr("Empty document or\nwrong password.\nContinue?"), tr("&No"), tr("&Yes."), 0 ) ) { case 0: // No retval = loadFinalize(); exitZs (1); break; case 1: // Yes break; } } retval = loadFinalize(); return true; } int ZSafe::loadInit(const char* _filename, const char *password) { unsigned int j = 0; unsigned int keylength=0; int count=0, count2=0, count3=0; unsigned char charbuf[8]; unsigned short ciphertext[4]; char key[128]; Krc2* krc2 = new Krc2(); fd = fopen (_filename, "rb"); QFileInfo f (_filename); load_buffer_length = f.size(); load_buffer_length = ((load_buffer_length / 1024)+1) * 1024 * 2; - if (fd == NULL) + if (fd == NULL) { + delete krc2; return PWERR_OPEN; + } buffer = (char *)malloc(load_buffer_length); for (j = 0; password[j] != '\0'; j++) { key[j] = password[j]; } keylength = j; krc2->rc2_expandkey (key, keylength, 128); #ifndef Q_WS_WIN size = read(fileno (fd), (unsigned char *) (charbuf + count), 8); #else size = fread ((unsigned char *) (charbuf + count), sizeof(unsigned char), 8, fd); #endif - if (size < 8) + if (size < 8) { + delete krc2; return PWERR_DATA; + } for (count = 0; count < 4; count++) { count2 = count << 1; iv[count] = charbuf[count2] << 8; iv[count] += charbuf[count2 + 1]; } size = 0; bufferIndex = 0; #ifndef Q_WS_WIN while ((count = read (fileno (fd), (unsigned char *) charbuf, 8)) > 0) { while (count < 8) { count2 = read (fileno (fd), (unsigned char *) (charbuf + count), 8); #else while ((count = fread ((unsigned char *) (charbuf), sizeof(unsigned char), 8, fd)) > 0) { while (count < 8) { count2 = fread ((unsigned char *) (charbuf + count), sizeof(unsigned char), 8, fd); #endif if (count2 == 0) { + delete krc2; return PWERR_DATA; } count += count2; } /* while (count < 8) */ size += 8; for (count2 = 0; count2 < 8; count2 += 2) { count3 = count2 >> 1; ciphertext[count3] = charbuf[count2] << 8; ciphertext[count3] += charbuf[count2 + 1]; plaintext[count3] = ciphertext[count3] ^ iv[count3]; iv[count3] = plaintext[count3]; } /* for (count2) */ krc2->rc2_decrypt (plaintext); memcpy ((unsigned char *) (buffer + bufferIndex), plaintext, 8); bufferIndex += 8; buffer[bufferIndex + 1] = '\0'; } /* while ((count = read (fileno (fd), (unsigned char *) charbuf, 8)) > 0) */ + delete krc2; size -= buffer[size - 1]; lastcount = 0; /* This will point to the starting index */ bufferIndex = 0; return PWERR_GOOD; } int ZSafe::loadEntry(char *entry[FIELD_SIZE]) { /* Strip off PKCS 5 padding * Should check to make sure it's good here */ int count, count1=0; for (count = lastcount; count < size; count++) { if ((unsigned char) (buffer[count]) == 255) { if (buffer[bufferIndex] == '\0') { bufferIndex++; } entry[count1] = (char *) malloc (count - bufferIndex + 1); memcpy (entry[count1], (unsigned char *) (buffer + bufferIndex), count - bufferIndex); entry[count1][count - bufferIndex] = '\0'; count++; bufferIndex = count; count1++; if (count1 == FIELD_SIZE) { lastcount = count; return 1; } } /* if ((unsigned char) (buffer[count]) == 255) */ } /* for (count = 0; count < size; count++) */ return 2; } int ZSafe::loadFinalize(void) { fclose (fd); if (buffer) free(buffer); return PWERR_GOOD; } bool ZSafe::saveDocument(const char* _filename, bool withPwd, const char* ) { if (filename.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("No document defined.\nYou have to create a new document")); return false; } // if (m_password.isEmpty()) // withPwd = true; // the document must be saved with a valid password if (withPwd) { bool pwdOk = FALSE; while (!pwdOk) { getDocPassword(tr("Enter Password")); if (m_password.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("Password is empty.\nPlease enter again.")); continue; } QString firstPasswd = m_password; getDocPassword(tr("Reenter Password")); if (m_password.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("Password is empty.\nPlease enter again.")); continue; } if (firstPasswd != m_password) { QMessageBox::critical( 0, tr("ZSafe"), tr("Passwords must be identical.\nPlease enter again.")); continue; } pwdOk = TRUE; modified = false; } } else if (modified) { QString fns(_filename); fns = fns.right (fns.length() - fns.findRev ('/') - 1); switch( QMessageBox::information( this, tr("ZSafe"), tr("Do you want to save ") + fns + tr("\nbefore continuing?"), tr("&Save"), tr("&Don't Save"), 0 // Enter == button 0 ) ) { // Escape == button 2 case 0: // Save clicked, Alt-S or Enter pressed. modified = false; break; case 1: // Don't Save clicked or Alt-D pressed modified = false; return true; } } modified = false; if (m_password.isEmpty()) return false; int retval = saveInit(_filename, m_password); // int retval = saveInit(_filename, "test"); if (retval != PWERR_GOOD) { return false; } char* entry[FIELD_SIZE]; // save the validation entry { int i=0; entry[i] = (char*)malloc(strlen("ZSAFECATEGORY")+1); strcpy(entry[i++], "ZSAFECATEGORY"); entry[i] = (char*)malloc(strlen("name")+1); strcpy(entry[i++], "name"); entry[i] = (char*)malloc(strlen("username")+1); strcpy(entry[i++], "username"); entry[i] = (char*)malloc(strlen("password")+1); strcpy(entry[i++], "password"); entry[i] = (char*)malloc(strlen("comment")+1); strcpy(entry[i++], "comment"); entry[i] = (char*)malloc(strlen("field5")+1); strcpy(entry[i++], "field5"); entry[i] = (char*)malloc(strlen("field6")+1); strcpy(entry[i++], "field6"); retval = saveEntry(entry); for (int z=0; z<i; z++) free(entry[z]); if (retval == PWERR_DATA) { #ifndef NO_OPIE owarn << "1: Error writing file, contents not saved" << oendl; #else qWarning("1: Error writing file, contents not saved"); #endif saveFinalize(); return false; } // #ifndef Q_WS_WIN conf->writeEntry(APP_KEY+"valzsafe", 1); // #endif saveConf(); } QListViewItem *i; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; si = si->nextSibling()) { int j=0; entry[j] = (char*)malloc(strlen(i->text(0).utf8())+1); strcpy(entry[j++], i->text(0).utf8()); entry[j] = (char*)malloc(strlen(si->text(0).utf8())+1); strcpy(entry[j++], si->text(0).utf8()); entry[j] = (char*)malloc(strlen(si->text(1).utf8())+1); strcpy(entry[j++], si->text(1).utf8()); entry[j] = (char*)malloc(strlen(si->text(2).utf8())+1); strcpy(entry[j++], si->text(2).utf8()); entry[j] = (char*)malloc(strlen(si->text(3).utf8())+1); strcpy(entry[j++], si->text(3).utf8()); entry[j] = (char*)malloc(strlen(si->text(4).utf8())+1); strcpy(entry[j++], si->text(4).utf8()); entry[j] = (char*)malloc(strlen(si->text(5).utf8())+1); strcpy(entry[j++], si->text(5).utf8()); retval = saveEntry(entry); for (int z=0; z<j; z++) { free(entry[z]); } if (retval == PWERR_DATA) { #ifndef NO_OPIE owarn << "1: Error writing file, contents not saved" << oendl; #else qWarning("1: Error writing file, contents not saved"); #endif saveFinalize(); return false; } } } if (saveFinalize() == PWERR_DATA) { #ifndef NO_OPIE owarn << "2: Error writing file, contents not saved" << oendl; #else qWarning("2: Error writing file, contents not saved"); #endif return false; } else { #ifndef DESKTOP Global::statusMessage (tr("Password file saved.")); #endif modified = false; return true; } } PasswordForm *newPwdDialog; bool newPwdDialogResult = false; void ZSafe::setPasswordDialogDone() { newPwdDialogResult = true; newPwdDialog->close(); } void ZSafe::getDocPassword(QString title) { // open the 'Password' dialog PasswordForm *dialog = new PasswordForm(this, title, TRUE); newPwdDialog = dialog; newPwdDialogResult = false; // QPixmap image0 = Opie::Core::OResource::loadPixmap( "zsafe/zsafe", Opie::Core::OResource::SmallIcon ); // dialog->setIcon( image0); connect( dialog->PasswordField, SIGNAL( returnPressed() ), this, SLOT( setPasswordDialogDone() ) ); // CS: !!! // int pos = filename.findRev ('/'); QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); dialog->setCaption(ti); // dialog->setCaption(title); dialog->PasswordField->setFocus(); QDialog::DialogCode result = (QDialog::DialogCode) dialog->exec(); QString password; if (result == QDialog::Accepted || newPwdDialogResult) { m_password = dialog->PasswordField->text(); } else { exitZs (1); } } int ZSafe::saveInit(const char *_filename, const char *password) { char key[128]; unsigned int j = 0; unsigned int keylength; // int val; int count2; Krc2* krc2 = new Krc2(); - /* first we should check the permissions of the filename */ -/* - if (QFile::exists(_filename)) { - val = checkFile(_filename); - if (val != PWERR_GOOD) - return val; - } else - { - val = creat (_filename, (S_IRUSR | S_IWUSR)); - if (val == -1) - return PWERR_OPEN; - else - close(val); - } -*/ QFileInfo f (_filename); save_buffer_length = f.size(); save_buffer_length = ((save_buffer_length / 1024)+1) * 1024; fd = fopen (_filename, "wb"); - if (fd == NULL) + if (fd == NULL) { + delete krc2; return PWERR_OPEN; + } buffer = (char*)malloc(save_buffer_length); /* make the key ready */ for (j = 0; password[j] != '\0'; j++) { key[j] = password[j]; } keylength = j; krc2->rc2_expandkey (key, keylength, 128); + delete krc2; /* First, we make the IV */ for (count2 = 0; count2 < 4; count2++) { iv[count2] = rand (); putc ((unsigned char) (iv[count2] >> 8), fd); putc ((unsigned char) (iv[count2] & 0xff), fd); } bufferIndex = 0; return PWERR_GOOD; } int ZSafe::saveEntry(char *entry[FIELD_SIZE]) { char *text1; int count2, count3; unsigned short ciphertext[4]; Krc2* krc2 = new Krc2(); buffer = (char*)memset(buffer, '\0', save_buffer_length); for (count2 = 0; count2 < FIELD_SIZE; count2++) { text1 = entry[count2]; if (strlen (text1) == 0) { strncat(buffer, " ", strlen(" ")); } else { strncat(buffer, text1, strlen(text1)); } /* Use 255 as the marker. \n is too tough to test for */ buffer[strlen (buffer)] = 255; } /*for (count2 = 0; count2 < 5; count2++)*/ count2 = 0; /* I'm using CBC mode and encrypting the data straight from top down. * At the bottom, encrypted, I will append an MD5 hash of the file, eventually. * PKCS 5 padding (explained at the code section */ while (count2 < (int)strlen (buffer)) { #ifndef WORDS_BIGENDIAN plaintext[bufferIndex] = buffer[count2 + 1] << 8; plaintext[bufferIndex] += buffer[count2] & 0xff; #endif #ifdef WORDS_BIGENDIAN plaintext[bufferIndex] = buffer[count2] << 8; plaintext[bufferIndex] += buffer[count2 + 1] & 0xff; #endif bufferIndex++; if (bufferIndex == 4) { krc2->rc2_encrypt (plaintext); for (count3 = 0; count3 < 4; count3++) { ciphertext[count3] = iv[count3] ^ plaintext[count3]; /* Now store the ciphertext as the iv */ iv[count3] = plaintext[count3]; /* reset the buffer index */ bufferIndex = 0; - if (putc ((unsigned char) (ciphertext[count3] >> 8), fd) == EOF) return PWERR_DATA; - if (putc ((unsigned char) (ciphertext[count3] & 0xff), fd) == EOF) return PWERR_DATA; + if (putc ((unsigned char) (ciphertext[count3] >> 8), fd) == EOF) { + delete krc2; + return PWERR_DATA; + } + if (putc ((unsigned char) (ciphertext[count3] & 0xff), fd) == EOF) { + delete krc2; + return PWERR_DATA; + } } /*for (count3 = 0; count3 < 5; count3++)*/ } /*if (bufferIndex == 5)*/ /* increment a short, not a byte */ count2 += 2; } /*while (count2 < strlen (buffer))*/ - int ret = PWERR_GOOD; - return ret; + delete krc2; + return PWERR_GOOD; } int ZSafe::saveFinalize(void) { int count1, retval = PWERR_GOOD; unsigned short ciphertext[4]; Krc2* krc2 = new Krc2(); /* Tack on the PKCS 5 padding * How it works is we fill up the last n bytes with the value n * * So, if we have, say, 13 bytes, 8 of which are used, we have 5 left * over, leaving us 3 short, so we fill it in with 3's. * * If we come out even, we fill it with 8 8s * * um, except that in this instance we are using 4 shorts instead of 8 bytes. * so, half everything */ for (count1 = bufferIndex; count1 < 4; count1++) { plaintext[count1] = (4 - bufferIndex); } krc2->rc2_encrypt (plaintext); for (count1 = 0; count1 < 4; count1++) { ciphertext[count1] = iv[count1] ^ plaintext[count1]; if (putc ((unsigned char) (ciphertext[count1] >> 8), fd) == EOF) retval = PWERR_DATA; if (putc ((unsigned char) (ciphertext[count1] & 0xff), fd) == EOF) retval = PWERR_DATA; } fclose (fd); free(buffer); + delete krc2; return retval; } void ZSafe::quitMe () { if (modified) { switch( QMessageBox::information( this, tr("ZSafe"), tr("Do you want to save\nbefore exiting?"), tr("&Save"), tr("S&ave with\nnew\npassword"), tr("&Don't Save"), 0 // Enter == button 0 ) ) { // Escape == button 2 case 0: // Save clicked, Alt-S or Enter pressed. // save modified = false; saveDocument(filename, FALSE); exitZs (1); break; case 1: // // Save with new password modified = false; saveDocument(filename, TRUE); exitZs (1); break; case 2: // Don't Save clicked or Alt-D pressed // don't save but exitZs exitZs (1); break; } } exitZs (1); } void ZSafe::categoryFieldActivated( const QString& category) { if (categoryDialog) setCategoryDialogFields(categoryDialog, category); } void ZSafe::addCategory() { if (filename.isEmpty()) { QMessageBox::critical( 0, tr("ZSafe"), tr("No document defined.\nYou have to create a new document")); return; } else { // open the 'Category' dialog bool initIcons = false; // open the 'Category' dialog CategoryDialog *dialog; if (categoryDialog) { dialog = categoryDialog; } else { categoryDialog = new CategoryDialog(this, tr("Category"), TRUE); dialog = categoryDialog; connect( dialog->CategoryField, SIGNAL( activated(const QString&)), this, SLOT( categoryFieldActivated(const QString&) ) ); initIcons = true; } // read all categories from the config file and store // into a list QFile f (cfgFile); QStringList list; if ( f.open(IO_ReadOnly) ) { // file opened successfully QTextStream t( &f ); // use a text stream QString s; while ( !t.eof() ) { // until end of file... s = t.readLine(); // line of text excluding '\n' list.append(s); } f.close(); } QStringList::Iterator it = list.begin(); QString categ; QString firstCategory; dialog->CategoryField->clear(); // remove all items while( it != list.end() ) { QString *cat = new QString (*it); if (cat->contains("-field1", FALSE)) { int pos = cat->find ("-field1"); cat->truncate(pos); categ = *cat; if (!categ.isEmpty()) { dialog->CategoryField->insertItem (categ, -1); if (firstCategory.isEmpty()) firstCategory = categ; } } ++it; } if (firstCategory.isEmpty()) setCategoryDialogFields(dialog); else setCategoryDialogFields(dialog, firstCategory); // CategoryDialog *dialog = new CategoryDialog(this, "Category", TRUE); if (initIcons) { Wait waitDialog(this, tr("Wait dialog")); waitDialog.waitLabel->setText(tr("Gathering icons...")); waitDialog.show(); qApp->processEvents(); QDir d(QPEApplication::qpeDir() + "pics/"); d.setFilter( QDir::Files); const QFileInfoList *list = d.entryInfoList(); QFileInfoListIterator it( *list ); // create list iterator QFileInfo *fi; // pointer for traversing dialog->IconField->insertItem("predefined"); while ( (fi=it.current()) ) { // for each file... QString fileName = fi->fileName(); if(fileName.right(4) == ".png"){ fileName = fileName.mid(0,fileName.length()-4); QPixmap imageOfFile(Opie::Core::OResource::loadPixmap(fileName,Opie::Core::OResource::SmallIcon)); dialog->IconField->insertItem(imageOfFile,fileName); } ++it; } waitDialog.hide(); } QDialog::DialogCode result = (QDialog::DialogCode) dialog->exec(); QString category; QString icon; QString fullIconPath; QPixmap *pix; if (result == QDialog::Accepted) { modified = true; category = dialog->CategoryField->currentText(); icon = dialog->IconField->currentText()+".png"; QListViewItem *li = new ShadedListItem( 1, ListView ); Category *c1 = new Category(); c1->setCategoryName(category); // if (!icon.isEmpty() && !icon.isNull()) if (icon != "predefined.png") { // build the full path fullIconPath = iconPath + icon; pix = new QPixmap (fullIconPath); // pix->resize(14, 14); if (!pix->isNull()) { // save the full pixmap name into the config file // #ifndef Q_WS_WIN conf->writeEntry(APP_KEY+category, icon); // #endif saveConf(); QImage img = pix->convertToImage(); pix->convertFromImage(img.smoothScale(14,14)); c1->setIcon (*pix); c1->setIconName(icon); } else { QPixmap folder( ( const char** ) general_data ); c1->setIcon (folder); } } else { c1->setIcon (*getPredefinedIcon(category)); } c1->setListItem (li); c1->initListItem(); categories.insert (c1->getCategoryName(), c1); saveCategoryDialogFields(dialog); } else { // delete dialog; dialog->hide(); return; } } } void ZSafe::delCategory() { if (!selectedItem) return; if (isCategory(selectedItem)) { switch( QMessageBox::information( this, tr("ZSafe"), tr("Do you want to delete?"), tr("&Delete"), tr("D&on't Delete"), 0 // Enter == button 0 ) ) { // Escape == button 2 case 0: // Delete clicked, Alt-S or Enter pressed. // Delete from the category list modified = true; categories.remove (selectedItem->text(0)); // #ifndef Q_WS_WIN conf->removeEntry (selectedItem->text(0)); // #endif saveConf(); // Delete the selected item and all subitems // step through all subitems QListViewItem *si; for (si = selectedItem->firstChild(); si != NULL; ) { QListViewItem *_si = si; si = si->nextSibling(); selectedItem->takeItem(_si); // remove from view list if (_si) delete _si; } ListView->takeItem(selectedItem); delete selectedItem; selectedItem = NULL; break; case 1: // Don't delete break; } } } void ZSafe::setCategoryDialogFields(CategoryDialog *dialog) { if (!dialog) return; QString icon; if (selectedItem) { dialog->Field1->setText(getFieldLabel (selectedItem, "1", tr("Name"))); dialog->Field2->setText(getFieldLabel (selectedItem, "2", tr("Username"))); dialog->Field3->setText(getFieldLabel (selectedItem, "3", tr("Password"))); dialog->Field4->setText(getFieldLabel (selectedItem, "4", tr("Comment"))); dialog->Field5->setText(getFieldLabel (selectedItem, "5", tr("Field 4"))); dialog->Field6->setText(getFieldLabel (selectedItem, "6", tr("Field 5"))); Category *cat= categories.find (selectedItem->text(0)); if (cat) { icon = cat->getIconName(); } else icon = conf->readEntry(APP_KEY+selectedItem->text(0)); } else { dialog->Field1->setText(tr("Name")); dialog->Field2->setText(tr("Username")); dialog->Field3->setText(tr("Password")); dialog->Field4->setText(tr("Comment")); dialog->Field5->setText(tr("Field 4")); dialog->Field6->setText(tr("Field 5")); } QDir d(QPEApplication::qpeDir() + "pics/"); d.setFilter( QDir::Files); const QFileInfoList *list = d.entryInfoList(); int i=0; QFileInfoListIterator it( *list ); // create list iterator QFileInfo *fi; // pointer for traversing if (icon.isEmpty() || icon.isNull()) { dialog->IconField->setCurrentItem(0); } else { while ( (fi=it.current()) ) { // for each file... QString fileName = fi->fileName(); if(fileName.right(4) == ".png") { fileName = fileName.mid(0,fileName.length()-4); if(fileName+".png"==icon) { dialog->IconField->setCurrentItem(i+1); break; } ++i; } ++it; } } } void ZSafe::setCategoryDialogFields(CategoryDialog *dialog, QString category) { if (!dialog) return; dialog->Field1->setText(getFieldLabel (category, "1", tr("Name"))); dialog->Field2->setText(getFieldLabel (category, "2", tr("Username"))); dialog->Field3->setText(getFieldLabel (category, "3", tr("Password"))); dialog->Field4->setText(getFieldLabel (category, "4", tr("Comment"))); dialog->Field5->setText(getFieldLabel (category, "5", tr("Field 4"))); dialog->Field6->setText(getFieldLabel (category, "6", tr("Field 5"))); QString icon; Category *cat= categories.find (category); if (cat) { icon = cat->getIconName(); } else icon = conf->readEntry(APP_KEY+category); QDir d(QPEApplication::qpeDir() + "pics/"); d.setFilter( QDir::Files); const QFileInfoList *list = d.entryInfoList(); int i=0; QFileInfoListIterator it( *list ); // create list iterator QFileInfo *fi; // pointer for traversing if (icon.isEmpty() || icon.isNull()) { dialog->IconField->setCurrentItem(0); } else { while ( (fi=it.current()) ) { // for each file... QString fileName = fi->fileName(); if(fileName.right(4) == ".png") { fileName = fileName.mid(0,fileName.length()-4); if(fileName+".png"==icon) { dialog->IconField->setCurrentItem(i+1); break; } ++i; } ++it; } } } void ZSafe::saveCategoryDialogFields(CategoryDialog *dialog) { QString app_key = APP_KEY; conf->setGroup( "fieldDefs" ); QString category = dialog->CategoryField->currentText(); // #ifndef Q_WS_WIN conf->writeEntry(app_key+category+"-field1", dialog->Field1->text()); conf->writeEntry(app_key+category+"-field2", dialog->Field2->text()); conf->writeEntry(app_key+category+"-field3", dialog->Field3->text()); conf->writeEntry(app_key+category+"-field4", dialog->Field4->text()); conf->writeEntry(app_key+category+"-field5", dialog->Field5->text()); conf->writeEntry(app_key+category+"-field6", dialog->Field6->text()); // #endif saveConf(); conf->setGroup ("zsafe"); } void ZSafe::editCategory() { if (!selectedItem) return; if (isCategory(selectedItem)) { QString category = selectedItem->text(0); bool initIcons = false; // open the 'Category' dialog CategoryDialog *dialog; if (categoryDialog) { dialog = categoryDialog; } else { categoryDialog = new CategoryDialog(this, tr("Category"), TRUE); dialog = categoryDialog; connect( dialog->CategoryField, SIGNAL( activated(const QString&)), this, SLOT( categoryFieldActivated(const QString&) ) ); initIcons = true; } setCategoryDialogFields(dialog); // read all categories from the config file and store // into a list QFile f (cfgFile); QStringList list; if ( f.open(IO_ReadOnly) ) { // file opened successfully QTextStream t( &f ); // use a text stream QString s; while ( !t.eof() ) { // until end of file... s = t.readLine(); // line of text excluding '\n' list.append(s); } f.close(); } QStringList::Iterator it = list.begin(); QString categ; dialog->CategoryField->clear(); // remove all items int i=0; bool foundCategory = false; while( it != list.end() ) { QString *cat = new QString (*it); if (cat->contains("-field1", FALSE)) { int pos = cat->find ("-field1"); cat->truncate(pos); categ = *cat; if (!categ.isEmpty()) { dialog->CategoryField->insertItem (categ, i); if (category.compare(categ) == 0) { dialog->CategoryField->setCurrentItem(i); foundCategory = true; } i++; } } ++it; } if (!foundCategory) { dialog->CategoryField->insertItem (category, i); dialog->CategoryField->setCurrentItem(i); } QString icon; Category *cat= categories.find (selectedItem->text(0)); if (cat) { icon = cat->getIconName(); } if (initIcons) { Wait waitDialog(this, tr("Wait dialog")); waitDialog.waitLabel->setText(tr("Gathering icons...")); waitDialog.show(); qApp->processEvents(); QDir d(QPEApplication::qpeDir() + "pics/"); d.setFilter( QDir::Files); const QFileInfoList *list = d.entryInfoList(); int i=0; QFileInfoListIterator it( *list ); // create list iterator QFileInfo *fi; // pointer for traversing if (icon.isEmpty() || icon.isNull()) { dialog->IconField->setCurrentItem(0); } dialog->IconField->insertItem("predefined"); while ( (fi=it.current()) ) { // for each file... QString fileName = fi->fileName(); if(fileName.right(4) == ".png") { fileName = fileName.mid(0,fileName.length()-4); QPixmap imageOfFile(Opie::Core::OResource::loadPixmap(fileName,Opie::Core::OResource::SmallIcon)); dialog->IconField->insertItem(imageOfFile,fileName); if(fileName+".png"==icon) dialog->IconField->setCurrentItem(i+1); ++i; } ++it; } waitDialog.hide(); } else { QDir d(QPEApplication::qpeDir() + "pics/"); d.setFilter( QDir::Files); const QFileInfoList *list = d.entryInfoList(); int i=0; QFileInfoListIterator it( *list ); // create list iterator QFileInfo *fi; // pointer for traversing if (icon.isEmpty() || icon.isNull()) { dialog->IconField->setCurrentItem(0); } else { while ( (fi=it.current()) ) { // for each file... QString fileName = fi->fileName(); if(fileName.right(4) == ".png") { fileName = fileName.mid(0,fileName.length()-4); if(fileName+".png"==icon) { dialog->IconField->setCurrentItem(i+1); break; } ++i; } ++it; } } } // dialog->show(); QDialog::DialogCode result = (QDialog::DialogCode) dialog->exec(); QString fullIconPath; QPixmap *pix; if (result == QDialog::Accepted) { modified = true; if (category != dialog->CategoryField->currentText()) { categories.remove (category); // #ifndef Q_WS_WIN conf->removeEntry(category); // #endif saveConf(); } category = dialog->CategoryField->currentText(); icon = dialog->IconField->currentText()+".png"; if (cat) { // if (!icon.isEmpty() && !icon.isNull()) if (icon != "predefined.png") { // build the full path fullIconPath = iconPath + icon; pix = new QPixmap (fullIconPath); if (!pix->isNull()) { // save the full pixmap name into the config file // #ifndef Q_WS_WIN conf->writeEntry(APP_KEY+category, icon); // #endif saveConf(); QImage img = pix->convertToImage(); pix->convertFromImage(img.smoothScale(14,14)); cat->setIconName (icon); cat->setIcon (*pix); } } else { // #ifndef Q_WS_WIN conf->removeEntry (category); // #endif saveConf(); cat->setIcon (*getPredefinedIcon(category)); } // change the category name of the selected category QListViewItem *catItem = cat->getListItem(); if (catItem) { catItem->setText( 0, tr( category ) ); cat->setCategoryName (tr(category)); cat->initListItem(); categories.insert (category, cat); } } saveCategoryDialogFields(dialog); } else { // delete dialog; dialog->hide(); return; } } } void ZSafe::cutItem() { if (!selectedItem) return; if (!isCategory(selectedItem)) { IsCut = true; copiedItem = selectedItem; } } void ZSafe::copyItem() { if (!selectedItem) return; if (!isCategory(selectedItem)) { IsCopy = true; copiedItem = selectedItem; } } // paste item into category void ZSafe::pasteItem() { if (!selectedItem) return; if (isCategory(selectedItem)) { modified = true; if (IsCut) { if (copiedItem) { // add the new item QListViewItem *i = new ShadedListItem (0, selectedItem); // i->setOpen (TRUE); i->setText (0, copiedItem->text(0)); i->setText (1, copiedItem->text(1)); i->setText (2, copiedItem->text(2)); i->setText (3, copiedItem->text(3)); i->setText (4, copiedItem->text(4)); i->setText (5, copiedItem->text(5)); selectedItem->setOpen( TRUE ); // remove the cutted item copiedItem->parent()->takeItem(copiedItem); selectedItem = NULL; } } else if (IsCopy) { if (copiedItem) { // add the new item QListViewItem *i = new ShadedListItem (0, selectedItem); // i->setOpen (TRUE); i->setText (0, copiedItem->text(0)); i->setText (1, copiedItem->text(1)); i->setText (2, copiedItem->text(2)); i->setText (3, copiedItem->text(3)); i->setText (4, copiedItem->text(4)); i->setText (5, copiedItem->text(5)); selectedItem->setOpen( TRUE ); } } } IsCut = false; IsCopy = false; } void ZSafe::newDocument() { // open the file dialog QString newFile = zsaveDialog(); // open the new document if (newFile && newFile.length() > 0 ) { // save the previous opened document if (!filename.isEmpty()) saveDocument(filename, FALSE); modified = true; // clear the password list QListViewItem *i; QListViewItem *c = NULL; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { if (c) delete c; // delete the previous category c = i; // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } if (c) delete c; // delete the previous category categories.clear(); // m_password = ""; selectedItem = NULL; filename = newFile; // save the current filename to the config file conf->setGroup("zsafe"); conf->writeEntry(APP_KEY+"document", filename); saveConf(); QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); this->setCaption(tr("ZSafe: ") + ti); // openDocument(filename); QMessageBox::information( this, tr("ZSafe"), tr("Now you have to enter\na password twice for your\nnewly created document."), tr("&OK"), 0); saveDocumentWithPwd(); } } void ZSafe::loadDocument() { // open the file dialog QMap<QString, QStringList> mimeTypes; mimeTypes.insert(tr("All"), QStringList() ); mimeTypes.insert(tr("ZSafe"), "zsafe/*" ); QString newFile = OFileDialog::getOpenFileName( OFileSelector::EXTENDED_ALL, QDir::homeDirPath() + "/Documents/application/zsafe", QString::null, mimeTypes, this, tr ("Open ZSafe document")); // open the new document if (newFile && newFile.length() > 0 ) { // save the previous opened document if (!filename.isEmpty()) saveDocument(filename, FALSE); // clear the password list QListViewItem *i; QListViewItem *c = NULL; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { if (c) delete c; // delete the previous category c = i; // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } if (c) delete c; // delete the previous category categories.clear(); m_password = ""; selectedItem = NULL; filename = newFile; // save the current filename to the config file conf->setGroup("zsafe"); conf->writeEntry(APP_KEY+"document", filename); saveConf(); QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); this->setCaption(tr("ZSafe: ") + ti); openDocument(filename); } } void ZSafe::saveDocumentAs() { QString newFile = zsaveDialog(); // open the new document if (newFile && newFile.length() > 0 ) { // save the previous opened document if (!filename.isEmpty()) saveDocument(filename, FALSE); selectedItem = NULL; filename = newFile; // save the current filename to the config file conf->setGroup("zsafe"); conf->writeEntry(APP_KEY+"document", filename); saveConf(); QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); this->setCaption(tr("ZSafe: ") + ti); QMessageBox::information( this, tr("ZSafe"), tr("Now you have to enter\na password twice for your\nnewly created document."), tr("&OK"), 0); saveDocumentWithPwd(); } } void ZSafe::saveDocumentWithoutPwd() { saveDocument(filename, FALSE); } void ZSafe::saveDocumentWithPwd() { saveDocument(filename, TRUE); } void ZSafe::setExpandFlag() { expandTree = !expandTree; file->setItemChecked('o', expandTree); conf->setGroup ("zsafePrefs"); // #ifndef Q_WS_WIN conf->writeEntry (APP_KEY+"expandTree", expandTree); // #endif saveConf(); } void ZSafe::paintEvent( QPaintEvent * ) { if (raiseFlag) { raiseFlag = false; raiseTimer.start (1, true); if (infoForm->isVisible()) infoForm->raise(); } } void ZSafe::slotRaiseTimer() { if (infoForm->isVisible()) infoForm->raise(); raiseFlag = true; } QPixmap * ZSafe::getPredefinedIcon(QString category) { QPixmap *pm; if (category == "Bank cards") pm = new QPixmap((const char**)bank_cards_data); else if (category == "Passwords") pm = new QPixmap((const char**)passwords_data); else if (category == "Software") pm = new QPixmap((const char**)software_data); else if (category == "General") pm = new QPixmap((const char**)general_data); else pm = new QPixmap((const char**)general_data); return pm; } void ZSafe::setDocument(const QString& fileref) { // stop the timer to prevent loading of the default document docuTimer.stop(); DocLnk link(fileref); if ( link.isValid() ) { // if (filename != link.file()) // saveDocument(filename, FALSE); filename = link.file(); } else { // if (filename != fileref) // saveDocument(filename, FALSE); filename = fileref; } // save the current filename to the config file conf->setGroup("zsafe"); conf->writeEntry(APP_KEY+"document", filename); saveConf(); QString ti = filename.right (filename.length() - filename.findRev ('/') - 1); this->setCaption(tr("ZSafe: ") + ti); // clear the password list QListViewItem *i; QListViewItem *c = NULL; // step through all categories for (i = ListView->firstChild(); i != NULL; i = i->nextSibling()) { if (c) delete c; // delete the previous category c = i; // step through all subitems QListViewItem *si; for (si = i->firstChild(); si != NULL; ) { QListViewItem *_si = si; si = si->nextSibling(); i->takeItem(_si); // remove from view list if (_si) delete _si; } } if (c) delete c; // delete the previous category categories.clear(); m_password = ""; selectedItem = NULL; openDocument(filename); } void ZSafe::ListPressed(int mouse, QListViewItem *item, const QPoint&, int column) { if(item ==0) return; switch (mouse) { case 1: break; case 2: { QClipboard *cb = QApplication::clipboard(); QIconSet copy_img = Opie::Core::OResource::loadPixmap( "copy", Opie::Core::OResource::SmallIcon ); QIconSet edit_img = Opie::Core::OResource::loadPixmap( "edit", Opie::Core::OResource::SmallIcon ); QPixmap folder_open_img = Opie::Core::OResource::loadPixmap( "folder_open", Opie::Core::OResource::SmallIcon ); QPixmap editdelete_img = Opie::Core::OResource::loadPixmap( "editdelete", Opie::Core::OResource::SmallIcon ); QPopupMenu *m = new QPopupMenu(this); int copyItem = m->insertItem( copy_img, tr( "Copy to Clipboard" )); int editItem = m->insertItem(edit_img, tr( "Edit" )); int showItem = m->insertItem(folder_open_img, tr( "Show Info" )); int cancelItem = m->insertItem( editdelete_img, tr( "Cancel" )); m->setFocus(); int me=m->exec( QPoint( QCursor::pos().x(), QCursor::pos().y() ) ) ; if(me == copyItem) { copyClip( item->text(column) ) ; } else if (me == cancelItem) { cb->clear(); } else if (me == editItem) { editPwd(); } else if (me == showItem) { showInfo(item); } } break; }; } void ZSafe::copyClip( const QString &text) { QClipboard *cb = QApplication::clipboard(); cb->setText( text); } QString ZSafe::zsaveDialog() { QString fn; QMap<QString, QStringList> mimeTypes; mimeTypes.insert(tr("All"), QStringList() ); mimeTypes.insert(tr("Text"), "text/*" ); fn = OFileDialog::getSaveFileName( OFileSelector::EXTENDED_ALL, QDir::homeDirPath() + "/Documents/application/zsafe", QString::null, mimeTypes, this, tr ("Export text file")); return fn; } diff --git a/noncore/comm/keypebble/vncauth.c b/noncore/comm/keypebble/vncauth.c index 277d145..7de837a 100644 --- a/noncore/comm/keypebble/vncauth.c +++ b/noncore/comm/keypebble/vncauth.c @@ -1,160 +1,164 @@ /* * Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory * * This 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 software 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. */ /* * vncauth.c - Functions for VNC password management and authentication. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <time.h> #include "vncauth.h" #include "d3des.h" /* * We use a fixed key to store passwords, since we assume that our local * file system is secure but nonetheless don't want to store passwords * as plaintext. */ unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7}; /* * Encrypt a password and store it in a file. Returns 0 if successful, * 1 if the file could not be written. */ int vncEncryptAndStorePasswd(char *passwd, char *fname) { FILE *fp; uint i; unsigned char encryptedPasswd[8]; if ((fp = fopen(fname,"w")) == NULL) return 1; chmod(fname, S_IRUSR|S_IWUSR); /* pad password with nulls */ for (i = 0; i < 8; i++) { if (i < strlen(passwd)) { encryptedPasswd[i] = passwd[i]; } else { encryptedPasswd[i] = 0; } } /* Do encryption in-place - this way we overwrite our copy of the plaintext password */ deskey(fixedkey, EN0); des(encryptedPasswd, encryptedPasswd); for (i = 0; i < 8; i++) { putc(encryptedPasswd[i], fp); } fclose(fp); return 0; } /* * Decrypt a password from a file. Returns a pointer to a newly allocated * string containing the password or a null pointer if the password could * not be retrieved for some reason. */ char * vncDecryptPasswdFromFile(char *fname) { FILE *fp; int i, ch; unsigned char *passwd = (unsigned char *)malloc(9); - if ((fp = fopen(fname,"r")) == NULL) return NULL; + if ((fp = fopen(fname,"r")) == NULL) { + free(passwd); + return NULL; + } for (i = 0; i < 8; i++) { ch = getc(fp); if (ch == EOF) { fclose(fp); + free(passwd); return NULL; } passwd[i] = ch; } deskey(fixedkey, DE1); des(passwd, passwd); passwd[8] = 0; return (char *)passwd; } /* * Generate CHALLENGESIZE random bytes for use in challenge-response * authentication. */ void vncRandomBytes(unsigned char *bytes) { int i; unsigned int seed = (unsigned int) time(0); srandom(seed); for (i = 0; i < CHALLENGESIZE; i++) { bytes[i] = (unsigned char)(random() & 255); } } /* * Encrypt CHALLENGESIZE bytes in memory using a password. */ void vncEncryptBytes(unsigned char *bytes, char *passwd) { unsigned char key[8]; int i; /* key is simply password padded with nulls */ for (i = 0; i < 8; i++) { if (i < strlen(passwd)) { key[i] = passwd[i]; } else { key[i] = 0; } } deskey(key, EN0); for (i = 0; i < CHALLENGESIZE; i += 8) { des(bytes+i, bytes+i); } } diff --git a/noncore/net/ftplib/ftplib.c b/noncore/net/ftplib/ftplib.c index efcd6f0..addf9d2 100644 --- a/noncore/net/ftplib/ftplib.c +++ b/noncore/net/ftplib/ftplib.c @@ -1,1350 +1,1354 @@ /***************************************************************************/ /* ftplib.c - callable ftp access routines */ /* Copyright (C) 1996-2000 Thomas Pfau, pfau@cnj.digex.net */ /* 73 Catherine Street, South Bound Brook, NJ, 08880 */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public */ /* License as published by the Free Software Foundation; either */ /* version 2 of the License, or (at your option) any later version. */ /* */ /* This library 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 */ /* Library General Public License for more details. */ /* */ /* You should have received a copy of the GNU Library General Public */ /* License along with this progam; if not, write to the */ /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ /* Boston, MA 02111-1307, USA. */ /* */ /***************************************************************************/ // changes made by Lorn Potter <llornkcor@handhelds.org> // #if defined(__unix__) || defined(__VMS) #include <unistd.h> #endif #if defined(_WIN32) #include <windows.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <ctype.h> #if defined(__unix__) #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #elif defined(VMS) #include <types.h> #include <socket.h> #include <in.h> #include <netdb.h> #include <inet.h> #elif defined(_WIN32) #include <winsock.h> #endif #define BUILDING_LIBRARY #include "ftplib.h" #if defined(_WIN32) #define SETSOCKOPT_OPTVAL_TYPE (const char *) #else #define SETSOCKOPT_OPTVAL_TYPE (void *) #endif #define FTPLIB_BUFSIZ 8192 #define ACCEPT_TIMEOUT 10 #define FTPLIB_CONTROL 0 #define FTPLIB_READ 1 #define FTPLIB_WRITE 2 #if !defined FTPLIB_DEFMODE #define FTPLIB_DEFMODE FTPLIB_PASSIVE #endif struct NetBuf { char *cput,*cget; int handle; int cavail,cleft; char *buf; int dir; netbuf *ctrl; netbuf *data; int cmode; struct timeval idletime; FtpCallback idlecb; void *idlearg; int xfered; int cbbytes; int xfered1; char response[256]; }; static char *version = "ftplib Release 3.1-1 9/16/00, copyright 1996-2000 Thomas Pfau"; GLOBALDEF int ftplib_debug = 0; #if defined(__unix__) || defined(VMS) #define net_read read #define net_write write #define net_close close #elif defined(_WIN32) #define net_read(x,y,z) recv(x,y,z,0) #define net_write(x,y,z) send(x,y,z,0) #define net_close closesocket #endif #if defined(NEED_MEMCCPY) /* * VAX C does not supply a memccpy routine so I provide my own */ void *memccpy(void *dest, const void *src, int c, size_t n) { int i=0; const unsigned char *ip=src; unsigned char *op=dest; while (i < n) { if ((*op++ = *ip++) == c) break; i++; } if (i == n) return NULL; return op; } #endif #if defined(NEED_STRDUP) /* * strdup - return a malloc'ed copy of a string */ char *strdup(const char *src) { int l = strlen(src) + 1; char *dst = malloc(l); if (dst) strcpy(dst,src); return dst; } #endif /* * socket_wait - wait for socket to receive or flush data * * return 1 if no user callback, otherwise, return value returned by * user callback */ static int socket_wait(netbuf *ctl) { fd_set fd,*rfd = NULL,*wfd = NULL; struct timeval tv; int rv = 0; if ((ctl->dir == FTPLIB_CONTROL) || (ctl->idlecb == NULL)) return 1; if (ctl->dir == FTPLIB_WRITE) wfd = &fd; else rfd = &fd; FD_ZERO(&fd); do { FD_SET(ctl->handle,&fd); tv = ctl->idletime; rv = select(ctl->handle+1, rfd, wfd, NULL, &tv); if (rv == -1) { rv = 0; strncpy(ctl->ctrl->response, strerror(errno), sizeof(ctl->ctrl->response)); break; } else if (rv > 0) { rv = 1; break; } } while ((rv = ctl->idlecb(ctl, ctl->xfered, ctl->idlearg))); return rv; } /* * read a line of text * * return -1 on error or bytecount */ static int readline(char *buf,int max,netbuf *ctl) { int x,retval = 0; char *end,*bp=buf; int eof = 0; if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ)) return -1; if (max == 0) return 0; do { if (ctl->cavail > 0) { x = (max >= ctl->cavail) ? ctl->cavail : max-1; end = memccpy(bp,ctl->cget,'\n',x); if (end != NULL) x = end - bp; retval += x; bp += x; *bp = '\0'; max -= x; ctl->cget += x; ctl->cavail -= x; if (end != NULL) { bp -= 2; if (strcmp(bp,"\r\n") == 0) { *bp++ = '\n'; *bp++ = '\0'; --retval; } break; } } if (max == 1) { *buf = '\0'; break; } if (ctl->cput == ctl->cget) { ctl->cput = ctl->cget = ctl->buf; ctl->cavail = 0; ctl->cleft = FTPLIB_BUFSIZ; } if (eof) { if (retval == 0) retval = -1; break; } if (!socket_wait(ctl)) return retval; if ((x = net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1) { perror("read"); retval = -1; break; } if (x == 0) eof = 1; ctl->cleft -= x; ctl->cavail += x; ctl->cput += x; } while (1); return retval; } /* * write lines of text * * return -1 on error or bytecount */ static int writeline(char *buf, int len, netbuf *nData) { int x, nb=0, w; char *ubp = buf, *nbp; char lc=0; if (nData->dir != FTPLIB_WRITE) return -1; nbp = nData->buf; for (x=0; x < len; x++) { if ((*ubp == '\n') && (lc != '\r')) { if (nb == FTPLIB_BUFSIZ) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ); if (w != FTPLIB_BUFSIZ) { printf("net_write(1) returned %d, errno = %d\n", w, errno); return(-1); } nb = 0; } nbp[nb++] = '\r'; } if (nb == FTPLIB_BUFSIZ) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ); if (w != FTPLIB_BUFSIZ) { printf("net_write(2) returned %d, errno = %d\n", w, errno); return(-1); } nb = 0; } nbp[nb++] = lc = *ubp++; } if (nb) { if (!socket_wait(nData)) return x; w = net_write(nData->handle, nbp, nb); if (w != nb) { printf("net_write(3) returned %d, errno = %d\n", w, errno); return(-1); } } return len; } /* * read a response from the server * * return 0 if first char doesn't match * return 1 if first char matches */ static int readresp(char c, netbuf *nControl) { char match[5]; if (readline(nControl->response,256,nControl) == -1) { perror("Control socket read failed"); return 0; } if (ftplib_debug > 1) fprintf(stderr,"%s",nControl->response); if (nControl->response[3] == '-') { strncpy(match,nControl->response,3); match[3] = ' '; match[4] = '\0'; do { if (readline(nControl->response,256,nControl) == -1) { perror("Control socket read failed"); return 0; } if (ftplib_debug > 1) fprintf(stderr,"%s",nControl->response); } while (strncmp(nControl->response,match,4)); } if (nControl->response[0] == c) return 1; return 0; } /* * FtpInit for stupid operating systems that require it (Windows NT) */ GLOBALDEF void FtpInit(void) { #if defined(_WIN32) WORD wVersionRequested; WSADATA wsadata; int err; wVersionRequested = MAKEWORD(1,1); if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0) fprintf(stderr,"Network failed to start: %d\n",err); #endif } /* * FtpLastResponse - return a pointer to the last response received */ GLOBALDEF char *FtpLastResponse(netbuf *nControl) { if ((nControl) && (nControl->dir == FTPLIB_CONTROL)) return nControl->response; return NULL; } /* * FtpConnect - connect to remote server * * return 1 if connected, 0 if not */ GLOBALDEF int FtpConnect(const char *host, netbuf **nControl) { int sControl, stat, flags, oldflags; struct sockaddr_in sin; struct hostent *phe; struct servent *pse; int on=1; netbuf *ctrl; char *lhost; char *pnum; struct timeval tv; fd_set wr; memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; lhost = strdup(host); pnum = strchr(lhost,':'); if (pnum == NULL) { #if defined(VMS) sin.sin_port = htons(21); #else if ((pse = getservbyname("ftp","tcp")) == NULL) { perror("getservbyname"); return 0; } sin.sin_port = pse->s_port; #endif } else { *pnum++ = '\0'; if (isdigit(*pnum)) sin.sin_port = htons(atoi(pnum)); else { pse = getservbyname(pnum,"tcp"); sin.sin_port = pse->s_port; } } if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1) { if ((phe = gethostbyname(lhost)) == NULL) { perror("gethostbyname"); return 0; } memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); } free(lhost); sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sControl == -1) { perror("socket"); return 0; } if ( setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1) { perror("setsockopt"); net_close(sControl); return 0; } //set nonblocking for connection timeout flags = fcntl( sControl, F_GETFL,0); oldflags=flags; fcntl( sControl, F_SETFL, O_NONBLOCK|flags); stat=connect( sControl, (struct sockaddr *)&sin, sizeof(sin)); if (stat < 0) { if (errno != EWOULDBLOCK && errno != EINPROGRESS) { perror("connect"); net_close(sControl); return 0; } } FD_ZERO(&wr); FD_SET( sControl, &wr); tv.tv_sec = ACCEPT_TIMEOUT; tv.tv_usec = 0; stat = select(sControl+1, 0, &wr, 0, &tv); if (stat < 1) { // time out has expired, // or an error has ocurred perror("timeout"); net_close(sControl); return 0; } printf("connected\n"); //set original flags fcntl( sControl, F_SETFL, oldflags); ctrl = calloc(1,sizeof(netbuf)); if (ctrl == NULL) { perror("calloc"); net_close(sControl); return 0; } ctrl->buf = malloc(FTPLIB_BUFSIZ); if (ctrl->buf == NULL) { perror("calloc"); net_close(sControl); free(ctrl); return 0; } ctrl->handle = sControl; ctrl->dir = FTPLIB_CONTROL; ctrl->ctrl = NULL; ctrl->cmode = FTPLIB_DEFMODE; ctrl->idlecb = NULL; ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0; ctrl->idlearg = NULL; ctrl->xfered = 0; ctrl->xfered1 = 0; ctrl->cbbytes = 0; if (readresp('2', ctrl) == 0) { net_close(sControl); free(ctrl->buf); free(ctrl); return 0; } *nControl = ctrl; return 1; } /* * FtpOptions - change connection options * * returns 1 if successful, 0 on error */ GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl) { int v,rv=0; switch (opt) { case FTPLIB_CONNMODE: v = (int) val; if ((v == FTPLIB_PASSIVE) || (v == FTPLIB_PORT)) { nControl->cmode = v; rv = 1; } break; case FTPLIB_CALLBACK: nControl->idlecb = (FtpCallback) val; rv = 1; break; case FTPLIB_IDLETIME: v = (int) val; rv = 1; nControl->idletime.tv_sec = v / 1000; nControl->idletime.tv_usec = (v % 1000) * 1000; break; case FTPLIB_CALLBACKARG: rv = 1; nControl->idlearg = (void *) val; break; case FTPLIB_CALLBACKBYTES: rv = 1; nControl->cbbytes = (int) val; break; } return rv; } /* * FtpSendCmd - send a command and wait for expected response * * return 1 if proper response received, 0 otherwise */ static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl) { char buf[256]; if (nControl->dir != FTPLIB_CONTROL) return 0; if (ftplib_debug > 2) fprintf(stderr,"%s\n",cmd); if ((strlen(cmd) + 3) > sizeof(buf)) return 0; sprintf(buf,"%s\r\n",cmd); if (net_write(nControl->handle,buf,strlen(buf)) <= 0) { perror("write"); return 0; } return readresp(expresp, nControl); } /* * FtpLogin - log in to remote server * * return 1 if logged in, 0 otherwise */ GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl) { char tempbuf[64]; if (((strlen(user) + 7) > sizeof(tempbuf)) || ((strlen(pass) + 7) > sizeof(tempbuf))) return 0; sprintf(tempbuf,"USER %s",user); if (!FtpSendCmd(tempbuf,'3',nControl)) { if (nControl->response[0] == '2') return 1; return 0; } sprintf(tempbuf,"PASS %s",pass); return FtpSendCmd(tempbuf,'2',nControl); } /* * FtpOpenPort - set up data connection * * return 1 if successful, 0 otherwise */ static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir) { int sData; union { struct sockaddr sa; struct sockaddr_in in; } sin; struct linger lng = { 0, 0 }; unsigned int l; int on=1; netbuf *ctrl; char *cp; unsigned int v[6]; char buf[256]; if (nControl->dir != FTPLIB_CONTROL) return -1; if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE)) { sprintf(nControl->response, "Invalid direction %d\n", dir); return -1; } if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE)) { sprintf(nControl->response, "Invalid mode %c\n", mode); return -1; } l = sizeof(sin); if (nControl->cmode == FTPLIB_PASSIVE) { memset(&sin, 0, l); sin.in.sin_family = AF_INET; if (!FtpSendCmd("PASV",'2',nControl)) return -1; cp = strchr(nControl->response,'('); if (cp == NULL) return -1; cp++; sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]); sin.sa.sa_data[2] = v[2]; sin.sa.sa_data[3] = v[3]; sin.sa.sa_data[4] = v[4]; sin.sa.sa_data[5] = v[5]; sin.sa.sa_data[0] = v[0]; sin.sa.sa_data[1] = v[1]; } else { if (getsockname(nControl->handle, &sin.sa, &l) < 0) { perror("getsockname"); return 0; } } sData = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); if (sData == -1) { perror("socket"); return -1; } if (setsockopt(sData,SOL_SOCKET,SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE &on,sizeof(on)) == -1) { perror("setsockopt"); net_close(sData); return -1; } if (setsockopt(sData,SOL_SOCKET,SO_LINGER, SETSOCKOPT_OPTVAL_TYPE &lng,sizeof(lng)) == -1) { perror("setsockopt"); net_close(sData); return -1; } if (nControl->cmode == FTPLIB_PASSIVE) { if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1) { perror("connect"); net_close(sData); return -1; } } else { sin.in.sin_port = 0; if (bind(sData, &sin.sa, sizeof(sin)) == -1) { perror("bind"); net_close(sData); return 0; } if (listen(sData, 1) < 0) { perror("listen"); net_close(sData); return 0; } if (getsockname(sData, &sin.sa, &l) < 0) return 0; sprintf(buf, "PORT %d,%d,%d,%d,%d,%d", (unsigned char) sin.sa.sa_data[2], (unsigned char) sin.sa.sa_data[3], (unsigned char) sin.sa.sa_data[4], (unsigned char) sin.sa.sa_data[5], (unsigned char) sin.sa.sa_data[0], (unsigned char) sin.sa.sa_data[1]); if (!FtpSendCmd(buf,'2',nControl)) { net_close(sData); return 0; } } ctrl = calloc(1,sizeof(netbuf)); if (ctrl == NULL) { perror("calloc"); net_close(sData); return -1; } if ((mode == 'A') && ((ctrl->buf = malloc(FTPLIB_BUFSIZ)) == NULL)) { perror("calloc"); net_close(sData); free(ctrl); return -1; } ctrl->handle = sData; ctrl->dir = dir; ctrl->idletime = nControl->idletime; ctrl->idlearg = nControl->idlearg; ctrl->xfered = 0; ctrl->xfered1 = 0; ctrl->cbbytes = nControl->cbbytes; if (ctrl->idletime.tv_sec || ctrl->idletime.tv_usec || ctrl->cbbytes) ctrl->idlecb = nControl->idlecb; else ctrl->idlecb = NULL; *nData = ctrl; return 1; } /* * FtpAcceptConnection - accept connection from server * * return 1 if successful, 0 otherwise */ static int FtpAcceptConnection(netbuf *nData, netbuf *nControl) { int sData; struct sockaddr addr; unsigned int l; int i; struct timeval tv; fd_set mask; int rv; FD_ZERO(&mask); FD_SET(nControl->handle, &mask); FD_SET(nData->handle, &mask); tv.tv_usec = 0; tv.tv_sec = ACCEPT_TIMEOUT; printf("<<<<<<<<<<<<<<<<%d\n",ACCEPT_TIMEOUT); i = nControl->handle; if (i < nData->handle) i = nData->handle; i = select(i+1, &mask, NULL, NULL, &tv); if (i == -1) { strncpy(nControl->response, strerror(errno), sizeof(nControl->response)); net_close(nData->handle); nData->handle = 0; rv = 0; } else if (i == 0) { strcpy(nControl->response, "timed out waiting for connection"); net_close(nData->handle); nData->handle = 0; rv = 0; } else { if (FD_ISSET(nData->handle, &mask)) { l = sizeof(addr); sData = accept(nData->handle, &addr, &l); i = errno; net_close(nData->handle); if (sData > 0) { rv = 1; nData->handle = sData; } else { strncpy(nControl->response, strerror(i), sizeof(nControl->response)); nData->handle = 0; rv = 0; } } else if (FD_ISSET(nControl->handle, &mask)) { net_close(nData->handle); nData->handle = 0; readresp('2', nControl); rv = 0; } } return rv; } /* * FtpAccess - return a handle for a data stream * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl, netbuf **nData) { char buf[256]; int dir; if ((path == NULL) && ((typ == FTPLIB_FILE_WRITE) || (typ == FTPLIB_FILE_READ))) { sprintf(nControl->response, "Missing path argument for file transfer\n"); return 0; } sprintf(buf, "TYPE %c", mode); if (!FtpSendCmd(buf, '2', nControl)) return 0; switch (typ) { case FTPLIB_DIR: strcpy(buf,"NLST"); dir = FTPLIB_READ; break; case FTPLIB_DIR_VERBOSE: strcpy(buf,"LIST"); dir = FTPLIB_READ; break; case FTPLIB_FILE_READ: strcpy(buf,"RETR"); dir = FTPLIB_READ; break; case FTPLIB_FILE_WRITE: strcpy(buf,"STOR"); dir = FTPLIB_WRITE; break; default: sprintf(nControl->response, "Invalid open type %d\n", typ); return 0; } if (path != NULL) { int i = strlen(buf); buf[i++] = ' '; if ((strlen(path) + i) >= sizeof(buf)) return 0; strcpy(&buf[i],path); } if (FtpOpenPort(nControl, nData, mode, dir) == -1) return 0; if (!FtpSendCmd(buf, '1', nControl)) { FtpClose(*nData); *nData = NULL; return 0; } (*nData)->ctrl = nControl; nControl->data = *nData; if (nControl->cmode == FTPLIB_PORT) { if (!FtpAcceptConnection(*nData,nControl)) { FtpClose(*nData); *nData = NULL; nControl->data = NULL; return 0; } } return 1; } /* * FtpRead - read from a data connection */ GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData) { int i; if (nData->dir != FTPLIB_READ) return 0; if (nData->buf) i = readline(buf, max, nData); else { i = socket_wait(nData); if (i != 1) return 0; i = net_read(nData->handle, buf, max); } if (i == -1) return 0; nData->xfered += i; if (nData->idlecb && nData->cbbytes) { nData->xfered1 += i; if (nData->xfered1 > nData->cbbytes) { if (nData->idlecb(nData, nData->xfered, nData->idlearg) == 0) return 0; nData->xfered1 = 0; } } return i; } /* * FtpWrite - write to a data connection */ GLOBALDEF int FtpWrite(void *buf, int len, netbuf *nData) { int i; if (nData->dir != FTPLIB_WRITE) return 0; if (nData->buf) i = writeline(buf, len, nData); else { if (socket_wait(nData) < 0) fprintf(stderr, "FtpWrite: socket_wait failed with %s\n", nData->ctrl->response); i = net_write(nData->handle, buf, len); } if (i == -1) return 0; nData->xfered += i; if (nData->idlecb && nData->cbbytes) { nData->xfered1 += i; if (nData->xfered1 > nData->cbbytes) { nData->idlecb(nData, nData->xfered, nData->idlearg); nData->xfered1 = 0; } } return i; } /* * FtpClose - close a data connection */ GLOBALDEF int FtpClose(netbuf *nData) { netbuf *ctrl; switch (nData->dir) { case FTPLIB_WRITE: /* potential problem - if buffer flush fails, how to notify user? */ if (nData->buf != NULL) writeline(NULL, 0, nData); case FTPLIB_READ: if (nData->buf) free(nData->buf); shutdown(nData->handle,2); net_close(nData->handle); ctrl = nData->ctrl; free(nData); if (ctrl) { ctrl->data = NULL; return(readresp('2', ctrl)); } return 1; case FTPLIB_CONTROL: if (nData->data) { nData->ctrl = NULL; FtpClose(nData); } net_close(nData->handle); free(nData); return 0; } return 1; } /* * FtpSite - send a SITE command * * return 1 if command successful, 0 otherwise */ GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl) { char buf[256]; if ((strlen(cmd) + 7) > sizeof(buf)) return 0; sprintf(buf,"SITE %s",cmd); if (!FtpSendCmd(buf,'2',nControl)) return 0; return 1; } /* * FtpSysType - send a SYST command * * Fills in the user buffer with the remote system type. If more * information from the response is required, the user can parse * it out of the response buffer returned by FtpLastResponse(). * * return 1 if command successful, 0 otherwise */ GLOBALDEF int FtpSysType(char *buf, int max, netbuf *nControl) { int l = max; char *b = buf; char *s; if (!FtpSendCmd("SYST",'2',nControl)) return 0; s = &nControl->response[4]; while ((--l) && (*s != ' ')) *b++ = *s++; *b++ = '\0'; return 1; } /* * FtpMkdir - create a directory at server * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl) { char buf[256]; if ((strlen(path) + 6) > sizeof(buf)) return 0; sprintf(buf,"MKD %s",path); if (!FtpSendCmd(buf,'2', nControl)) return 0; return 1; } /* * FtpChdir - change path at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpChdir(const char *path, netbuf *nControl) { char buf[256]; if ((strlen(path) + 6) > sizeof(buf)) return 0; sprintf(buf,"CWD %s",path); if (!FtpSendCmd(buf,'2',nControl)) return 0; return 1; } /* * FtpCDUp - move to parent directory at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpCDUp(netbuf *nControl) { if (!FtpSendCmd("CDUP",'2',nControl)) return 0; return 1; } /* * FtpRmdir - remove directory at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl) { char buf[256]; if ((strlen(path) + 6) > sizeof(buf)) return 0; sprintf(buf,"RMD %s",path); if (!FtpSendCmd(buf,'2',nControl)) return 0; return 1; } /* * FtpPwd - get working directory at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpPwd(char *path, int max, netbuf *nControl) { int l = max; char *b = path; char *s; if (!FtpSendCmd("PWD",'2',nControl)) return 0; s = strchr(nControl->response, '"'); if (s == NULL) return 0; s++; while ((--l) && (*s) && (*s != '"')) *b++ = *s++; *b++ = '\0'; return 1; } /* * FtpXfer - issue a command and transfer data * * return 1 if successful, 0 otherwise */ static int FtpXfer(const char *localfile, const char *path, netbuf *nControl, int typ, int mode) { int l,c; char *dbuf; FILE *local = NULL; netbuf *nData; int rv=1; if (localfile != NULL) { char ac[4] = "w"; if (typ == FTPLIB_FILE_WRITE) ac[0] = 'r'; if (mode == FTPLIB_IMAGE) ac[1] = 'b'; local = fopen(localfile, ac); if (local == NULL) { strncpy(nControl->response, strerror(errno), sizeof(nControl->response)); return 0; } } if (local == NULL) local = (typ == FTPLIB_FILE_WRITE) ? stdin : stdout; if (!FtpAccess(path, typ, mode, nControl, &nData)) + { + if (localfile != NULL) + fclose(local); return 0; + } dbuf = malloc(FTPLIB_BUFSIZ); if (typ == FTPLIB_FILE_WRITE) { while ((l = fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0) if ((c = FtpWrite(dbuf, l, nData)) < l) { printf("short write: passed %d, wrote %d\n", l, c); rv = 0; break; } } else { while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0) if (fwrite(dbuf, 1, l, local) <= 0) { perror("localfile write"); rv = 0; break; } } free(dbuf); fflush(local); if (localfile != NULL) fclose(local); FtpClose(nData); return rv; } /* * FtpNlst - issue an NLST command and write response to output * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpNlst(const char *outputfile, const char *path, netbuf *nControl) { return FtpXfer(outputfile, path, nControl, FTPLIB_DIR, FTPLIB_ASCII); } /* * FtpDir - issue a LIST command and write response to output * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpDir(const char *outputfile, const char *path, netbuf *nControl) { return FtpXfer(outputfile, path, nControl, FTPLIB_DIR_VERBOSE, FTPLIB_ASCII); } /* * FtpSize - determine the size of a remote file * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpSize(const char *path, int *size, char mode, netbuf *nControl) { char cmd[256]; int resp,sz,rv=1; if ((strlen(path) + 7) > sizeof(cmd)) return 0; sprintf(cmd, "TYPE %c", mode); if (!FtpSendCmd(cmd, '2', nControl)) return 0; sprintf(cmd,"SIZE %s",path); if (!FtpSendCmd(cmd,'2',nControl)) rv = 0; else { if (sscanf(nControl->response, "%d %d", &resp, &sz) == 2) *size = sz; else rv = 0; } return rv; } /* * FtpModDate - determine the modification date of a remote file * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl) { char buf[256]; int rv = 1; if ((strlen(path) + 7) > sizeof(buf)) return 0; sprintf(buf,"MDTM %s",path); if (!FtpSendCmd(buf,'2',nControl)) rv = 0; else strncpy(dt, &nControl->response[4], max); return rv; } /* * FtpGet - issue a GET command and write received data to output * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpGet(const char *outputfile, const char *path, char mode, netbuf *nControl) { return FtpXfer(outputfile, path, nControl, FTPLIB_FILE_READ, mode); } /* * FtpPut - issue a PUT command and send data from input * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpPut(const char *inputfile, const char *path, char mode, netbuf *nControl) { return FtpXfer(inputfile, path, nControl, FTPLIB_FILE_WRITE, mode); } /* * FtpRename - rename a file at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl) { char cmd[256]; if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd))) return 0; sprintf(cmd,"RNFR %s",src); if (!FtpSendCmd(cmd,'3',nControl)) return 0; sprintf(cmd,"RNTO %s",dst); if (!FtpSendCmd(cmd,'2',nControl)) return 0; return 1; } /* * FtpDelete - delete a file at remote * * return 1 if successful, 0 otherwise */ GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl) { char cmd[256]; if ((strlen(fnm) + 7) > sizeof(cmd)) return 0; sprintf(cmd,"DELE %s",fnm); if (!FtpSendCmd(cmd,'2', nControl)) return 0; return 1; } /* * FtpQuit - disconnect from remote * * return 1 if successful, 0 otherwise */ GLOBALDEF void FtpQuit(netbuf *nControl) { if (nControl->dir != FTPLIB_CONTROL) return; if (FtpSendCmd("QUIT",'2',nControl) == 1) { if (ftplib_debug > 2) fprintf(stderr, "FtpQuit: FtpSendCmd(QUIT) failed\n"); } net_close(nControl->handle); free(nControl->buf); free(nControl); } diff --git a/noncore/todayplugins/stockticker/libstocks/csv.c b/noncore/todayplugins/stockticker/libstocks/csv.c index 86d8607..110df7c 100644 --- a/noncore/todayplugins/stockticker/libstocks/csv.c +++ b/noncore/todayplugins/stockticker/libstocks/csv.c @@ -1,406 +1,480 @@ /* libstocks - Library to get current stock quotes from Yahoo Finance * * Copyright (C) 2000 Eric Laeuffer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define __CSV_C__ #ifndef __UNIX__ #define __UNIX__ #endif #include <string.h> #include <stdlib.h> #include <stdio.h> #ifdef __WINDOWS__ #include <mbstring.h> #endif #include "csv.h" #include "stocks.h" #include "lists.h" #define DATE_LENGTH 7 /*YYMMDD*/ const char *months[12]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /*****************************************************************************/ /* Replacement of the strtok function. This one forgets "delim" when it is */ /* between two commas. */ /* Thanks to Julio Lucas who has told me the bug and has proposed me a patch */ /*****************************************************************************/ char *csv_strtok(char *s, char *delim) { static char *next=NULL; char *temp, *first; int comma=0; if (s!=NULL) first=s; else first=next; temp=first; if (*temp=='\0') return NULL; while (*temp!='\0' && ((*temp!=*delim) || comma)) { if (*temp=='"') comma ^= 1; temp++; } if (*temp=='\0') next=temp; else { *temp='\0'; next=temp+1; } return first; } /*****************************************************************************/ /* Parses the csv file and return a list of stocks structure. */ /* *csv points on the csv file in memory */ /* count defines the country, because csv depends on the country */ /*****************************************************************************/ stock *parse_csv_file(char *csv) { char *line; char *end_line; char *ptr; char *date; char *time; char *name; char *symbol; stock *StockPtr=NULL; stock *LastStockPtr=NULL; /* Used to return the pointer to the list */ stock *FirstStockPtr=NULL; /* used to see if symbol is valid */ int valid; char *test; line = csv; end_line = csv; while ((end_line = strstr(line, "\n"))) { *end_line = 0; /* Check if symbol valid */ /* if 1 "N/A" then ok because Indices have N/A for volume */ /* if 4 "N/A" then ok because Mutual funds have */ /* if 5 "N/A" then ok because currencies have */ /* So if >5 then stock not valid */ test = line; valid = 0; while ( (test = strstr(test, "N/A")) ) { valid ++; test = test +3; } if (valid < 6) { /* This Symbol is valid */ StockPtr = malloc_stock(); ptr = csv_strtok(line, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } symbol = (char *)malloc(strlen(ptr)+1); if (symbol==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy((char *)(symbol), ptr); StockPtr->Symbol = symbol; ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } name = (char *)malloc(strlen(ptr)+1); if (name==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy((char *)(name), ptr); StockPtr->Name = name; ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->CurrentPrice)); ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } date = (char *)malloc(strlen(ptr)+1); if (date==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy((char *)(date), ptr); StockPtr->Date = date; ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } time = (char *)malloc(strlen(ptr)+1); if (time==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy((char *)(time), ptr); StockPtr->Time = time; ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->Variation)); StockPtr->Pourcentage = 100 * StockPtr->Variation / (StockPtr->CurrentPrice - StockPtr->Variation); StockPtr->LastPrice = StockPtr->CurrentPrice - StockPtr->Variation; ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->OpenPrice)); ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->MaxPrice)); ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->MinPrice)); ptr = csv_strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } StockPtr->Volume = atoi(ptr); if( !FirstStockPtr ) { FirstStockPtr = StockPtr; StockPtr->PreviousStock = 0; } StockPtr->NextStock = 0; if (LastStockPtr) { LastStockPtr->NextStock = StockPtr; StockPtr->PreviousStock = LastStockPtr; } LastStockPtr = StockPtr; } else { /* this symbol is not valid */ /* Set the stock struct just with Symbol, all other are NULL */ /* This can be used to see if the symbol has been reached are not */ StockPtr = malloc_stock(); ptr = csv_strtok(line, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + return 0; + } symbol = (char *)malloc(strlen(ptr)+1); if (symbol==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy((char *)(symbol), ptr); StockPtr->Symbol = symbol; if( !FirstStockPtr ) { FirstStockPtr = StockPtr; StockPtr->PreviousStock = 0; } StockPtr->NextStock = 0; if (LastStockPtr) { LastStockPtr->NextStock = StockPtr; StockPtr->PreviousStock = LastStockPtr; } LastStockPtr = StockPtr; } end_line++; line = end_line; } return (FirstStockPtr); } /*****************************************************************************/ /* Parses the history quotes file and return a stock structure list. */ /*****************************************************************************/ stock *parse_csv_history_file(char *csv_file) { char *line; char *end_line; char *ptr; int day; char smonth[10]; int month; int year; char *date; int i; int test; stock *StockPtr=NULL; stock *LastStockPtr=NULL; /* Used to return the pointer to the list */ stock *FirstStockPtr=NULL; line = csv_file; end_line = csv_file; /* do not use the first line */ if (!(end_line = strstr(line, "\n"))) return 0; *end_line = 0; end_line++; line = end_line; while ((end_line = strstr(line, "\n"))) { *end_line = 0; StockPtr = malloc_stock(); /* Date */ ptr = strtok(line, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + free_stock(FirstStockPtr); + free_stock(LastStockPtr); + return 0; + } sscanf(ptr,"%d-%3s-%d",&day,smonth,&year); i=0; #ifdef __UNIX__ while((test=strcasecmp(months[i], smonth))) i++; #elif __WINDOWS__ while(test=_mbsnbicmp(months[i], smonth, strlen(months[i]))) i++; #endif month = i+1; date = (char *)malloc(DATE_LENGTH); if (date==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } sprintf(date,"%.2d%.2d%.2d", year, month, day); StockPtr->Date = date; /* Open */ ptr = strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + free_stock(FirstStockPtr); + free_stock(LastStockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->OpenPrice)); /* High */ ptr = strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + free_stock(FirstStockPtr); + free_stock(LastStockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->MaxPrice)); /* Low */ ptr = strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + free_stock(FirstStockPtr); + free_stock(LastStockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->MinPrice)); /* Close */ ptr = strtok(NULL, ","); - if (!ptr) return 0; + if (!ptr) + { + free_stock(StockPtr); + free_stock(FirstStockPtr); + free_stock(LastStockPtr); + return 0; + } sscanf(ptr,"%f",&(StockPtr->LastPrice)); /* Volume */ ptr = strtok(NULL, ","); if (!ptr) /* It seems to be an indice */ /* No volume for indices */ StockPtr->Volume = 0; else StockPtr->Volume = atoi(ptr); if( !FirstStockPtr ) { FirstStockPtr = StockPtr; StockPtr->PreviousStock = 0; } StockPtr->NextStock = 0; if (LastStockPtr) { LastStockPtr->NextStock = StockPtr; StockPtr->PreviousStock = LastStockPtr; } LastStockPtr = StockPtr; end_line++; line = end_line; } return (FirstStockPtr); } diff --git a/noncore/todayplugins/stockticker/libstocks/currency.c b/noncore/todayplugins/stockticker/libstocks/currency.c index 9a08a9d..e0090e2 100644 --- a/noncore/todayplugins/stockticker/libstocks/currency.c +++ b/noncore/todayplugins/stockticker/libstocks/currency.c @@ -1,66 +1,67 @@ /* libstocks - Library to get current stock quotes from Yahoo Finance * * Copyright (C) 2000 Eric Laeuffer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define __CURRENCY_C__ #include <stdio.h> #include <string.h> #include <malloc.h> #include <stdlib.h> #include "stocks.h" /*****************************************************************************/ /* returns the currency exchange rate of "from" currency into */ /* "into" currency. */ /*****************************************************************************/ libstocks_return_code get_currency_exchange(char *from, char *into, float *exchange) { char *symbol; stock *data; libstocks_return_code error; if((symbol = (char *)malloc(strlen(from)+strlen(into)+3))==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy(symbol, from); strcat(symbol, into); strcat(symbol, "=X"); error = get_stocks(symbol, &data); + free(symbol); if (error) { *exchange = 0; return(error); } free_stocks(data); *exchange = data->CurrentPrice; return(error); } diff --git a/noncore/todayplugins/stockticker/libstocks/lists.h b/noncore/todayplugins/stockticker/libstocks/lists.h index 0132317..a0eb434 100644 --- a/noncore/todayplugins/stockticker/libstocks/lists.h +++ b/noncore/todayplugins/stockticker/libstocks/lists.h @@ -1,35 +1,36 @@ /* libstocks - Library to get current stock quotes from Yahoo Finance * * Copyright (C) 2000 Eric Laeuffer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef __LISTS_H__ #define __LISTS_H__ #ifndef __LISTS_C__ #define PUBEXT_LISTS extern #else #define PUBEXT_LISTS #endif #include "stocks.h" PUBEXT_LISTS stock *malloc_stock(void); +PUBEXT_LISTS void free_stock(stock*); #endif /* __LISTS_H */ diff --git a/noncore/todayplugins/stockticker/libstocks/stocks.c b/noncore/todayplugins/stockticker/libstocks/stocks.c index eb04ba9..3a26a47 100644 --- a/noncore/todayplugins/stockticker/libstocks/stocks.c +++ b/noncore/todayplugins/stockticker/libstocks/stocks.c @@ -1,347 +1,348 @@ /* libstocks - Library to get current stock quotes from Yahoo Finance * * Copyright (C) 2000 Eric Laeuffer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #define __STOCKS_C__ #include <stdio.h> #include <string.h> #include <malloc.h> #include <stdlib.h> #ifdef __WINDOWS__ #include <mbstring.h> #endif #include "http.h" #include "csv.h" #include "stocks.h" /* s = symbol n = name l1 = last trade d1 = date t1 = time c1 = variation o = open h = higher price g = lower price v = volume */ const char yahoo_us_stocks_server[]="finance.yahoo.com"; const char yahoo_eu_stocks_server[]="finance.yahoo.com"; //const char yahoo_eu_stocks_server[]="fr.finance.yahoo.com"; const char yahoo_url_beg[]="/d/quotes.csv?s="; const char yahoo_url_end[]="&f=snl1d1t1c1ohgv&e=.csv"; typedef enum { YAHOO_EUROPE, YAHOO_US } yahoo_source; #define YAHOO_US_EXT_NB 11 const char *yahoo_us_ext[YAHOO_US_EXT_NB] = { ".US", /* United States */ ".TO", /* Canada */ ".M", /* Canada */ ".V", /* Canada */ ".AL", /* Canada */ ".MX", /* Mexico */ ".SA", /* Brasil */ ".BA", /* Argentina */ ".CR", /* Venezuela */ ".SN", /* Chili */ ".AX" /* Australia */ }; /*****************************************************************************/ /* Finds, according to the symbol extension, the http source of the quotes. */ /* Actually just finance.yahoo.com and fr.finance.yahoo.com are supported. */ /* The function returns the country source (US or EUROPE). */ /*****************************************************************************/ yahoo_source find_yahoo_source(char *symbol) { char *ptr; int i; int test; ptr = strrchr(symbol, '.'); /* If no extension we suppose it is a US stock */ if (!ptr) return YAHOO_US; /* extension is found */ /* Test if it is canadian stock */ for (i=0; i<YAHOO_US_EXT_NB; i++) { #ifdef __UNIX__ test = strcasecmp(yahoo_us_ext[i], ptr); #elif __WINDOWS__ test = _mbsnbicmp(yahoo_us_ext[i], ptr, strlen(yahoo_us_ext[i])); #endif if (!test) return YAHOO_US; } /* We suppose now it is a European stock */ return YAHOO_EUROPE; } /*****************************************************************************/ /* Gets quotes csv file, parses the file and create the quotes list */ /* *stocks points to the stocks to fetch */ /* *stock_datas points to the beginning of the list */ /* count allows to connect to all country servers */ /*****************************************************************************/ libstocks_return_code download_stocks(char *stocks, stock **stock_datas, yahoo_source source) { char *stocks_server=NULL; char *url_beg=NULL; char *url_end=NULL; char *url; char *data; libstocks_return_code error; #ifdef DEBUG printf("*download_stocks\n"); #endif switch (source) { case YAHOO_US: stocks_server = (char *)yahoo_us_stocks_server; break; case YAHOO_EUROPE: stocks_server = (char *)yahoo_eu_stocks_server; break; default: stocks_server = (char *)yahoo_us_stocks_server; break; } url_beg = (char *)yahoo_url_beg; url_end = (char *)yahoo_url_end; url = (char *)malloc(strlen(url_beg) +strlen(url_end) +strlen(stocks)+1); if (url==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy(url, url_beg); strcat(url, stocks); strcat(url, url_end); error=http_get(url, stocks_server, &data); free(url); if (error) return error; *stock_datas = parse_csv_file(data); free(data); if (!(*stock_datas)) return ERRPCSV; return 0; } /*****************************************************************************/ /* Gets quotes from yahoo */ /* Choses to fetch European or US depending on the symbol extension */ /* and merges the two lists to one */ /* *stocks points to the stocks to fetch */ /* *stock_datas points to the beginning of the list */ /*****************************************************************************/ libstocks_return_code get_stocks(const char *stocks, stock **stock_datas) { char *tok_ptr; char *eu_quotes=NULL; char *eu_quotes_temp=NULL; int lgr_eu_quotes=0; char *us_quotes=NULL; char *us_quotes_temp=NULL; int lgr_us_quotes=0; char *symbol; yahoo_source source; int lgr_symbol=0; libstocks_return_code error; stock *stocks_tmp=NULL; stock *stocks_tmp2=NULL; stock *stocks_getted=NULL; stock *last_stock=NULL; #ifdef DEBUG printf("*get_stocks\n"); #endif /* to preserve stocks */ tok_ptr = malloc(strlen(stocks)+1); if(tok_ptr==NULL) { fprintf(stderr,"Memory allocating error (%s line %d)\n" ,__FILE__, __LINE__); exit(1); } strcpy(tok_ptr, stocks); while( (symbol = strtok(tok_ptr, "+"))!=0) { /* clear tok_ptr for next strtok */ tok_ptr = NULL; /* look for "." in the symbol */ source = find_yahoo_source(symbol); switch (source) { case YAHOO_US: - if (us_quotes) { lgr_us_quotes = strlen(us_quotes); lgr_symbol = strlen(symbol); us_quotes_temp = malloc(lgr_us_quotes + lgr_symbol +2); if(us_quotes_temp==NULL) { - fprintf(stderr,"Memory allocating error (%s line %d)\n" - ,__FILE__, __LINE__); + fprintf(stderr,"Memory allocating error (%s line %d)\n", + __FILE__, __LINE__); exit(1); } strcpy(us_quotes_temp, us_quotes); strcat(us_quotes_temp,"+"); strcat(us_quotes_temp,symbol); free(us_quotes); us_quotes = us_quotes_temp; } else { us_quotes = malloc(strlen(symbol)+1); if(us_quotes==NULL) { - fprintf(stderr,"Memory allocating error (%s line %d)\n" - ,__FILE__, __LINE__); + fprintf(stderr,"Memory allocating error (%s line %d)\n", + __FILE__, __LINE__); exit(1); } strcpy(us_quotes, symbol); } break; case YAHOO_EUROPE: - if (eu_quotes) { lgr_eu_quotes = strlen(eu_quotes); lgr_symbol = strlen(symbol); eu_quotes_temp = malloc(lgr_eu_quotes + lgr_symbol +2); if(eu_quotes_temp==NULL) { - fprintf(stderr,"Memory allocating error (%s line %d)\n" - ,__FILE__, __LINE__); + fprintf(stderr,"Memory allocating error (%s line %d)\n", + __FILE__, __LINE__); exit(1); } strcpy(eu_quotes_temp, eu_quotes); strcat(eu_quotes_temp, "+"); strcat(eu_quotes_temp, symbol); free(eu_quotes); eu_quotes = eu_quotes_temp; } else { eu_quotes = malloc(strlen(symbol)+1); if(eu_quotes==NULL) { - fprintf(stderr,"Memory allocating error (%s line %d)\n" - ,__FILE__, __LINE__); + fprintf(stderr,"Memory allocating error (%s line %d)\n", + __FILE__, __LINE__); exit(1); } strcpy(eu_quotes, symbol); } break; } } free(tok_ptr); if (us_quotes) { /* Gets us quotes */ error = download_stocks(us_quotes, &stocks_tmp, YAHOO_US); + free(us_quotes); if (error) return error; } if (eu_quotes) { /* Gets european quotes */ error = download_stocks(eu_quotes, &stocks_getted, YAHOO_EUROPE); + free(eu_quotes); if (error) return error; /* concats lists if needed */ if (stocks_tmp) { stocks_tmp2 = stocks_tmp; while(stocks_tmp2 != NULL) { last_stock = stocks_tmp2; stocks_tmp2 = next_stock(stocks_tmp2); } last_stock->NextStock = stocks_getted; stocks_getted->PreviousStock = last_stock; } - else (stocks_tmp = stocks_getted); + else + (stocks_tmp = stocks_getted); } *stock_datas = stocks_tmp; return(0); } diff --git a/rsync/delta.c b/rsync/delta.c index 323c079..42f3afb 100644 --- a/rsync/delta.c +++ b/rsync/delta.c @@ -1,351 +1,353 @@ /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- * * librsync -- library for network deltas * $Id$ * * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* | Let's climb to the TOP of that | MOUNTAIN and think about STRIP | MINING!! */ /* * delta.c -- Generate in streaming mode an rsync delta given a set of * signatures, and a new file. * * The size of blocks for signature generation is determined by the * block size in the incoming signature. * * To calculate a signature, we need to be able to see at least one * block of the new file at a time. Once we have that, we calculate * its weak signature, and see if there is any block in the signature * hash table that has the same weak sum. If there is one, then we * also compute the strong sum of the new block, and cross check that. * If they're the same, then we can assume we have a match. * * The final block of the file has to be handled a little differently, * because it may be a short match. Short blocks in the signature * don't include their length -- we just allow for the final short * block of the file to match any block in the signature, and if they * have the same checksum we assume they must have the same length. * Therefore, when we emit a COPY command, we have to send it with a * length that is the same as the block matched, and not the block * length from the signature. */ /* * Profiling results as of v1.26, 2001-03-18: * * If everything matches, then we spend almost all our time in * rs_mdfour64 and rs_weak_sum, which is unavoidable and therefore a * good profile. * * If nothing matches, it is not so good. */ #include <config_rsync.h> #include <assert.h> #include <stdlib.h> #include <stdio.h> #include "rsync.h" #include "emit.h" #include "stream.h" #include "util.h" #include "sumset.h" #include "job.h" #include "trace.h" #include "checksum.h" #include "search.h" #include "types.h" /** * Turn this on to make all rolling checksums be checked from scratch. */ int rs_roll_paranoia = 0; static rs_result rs_delta_scan(rs_job_t *, rs_long_t avail_len, void *); static rs_result rs_delta_s_deferred_copy(rs_job_t *job); static rs_result rs_delta_s_end(rs_job_t *job) { rs_emit_end_cmd(job); return RS_DONE; } /** * \brief Get a block of data if possible, and see if it matches. * * On each call, we try to process all of the input data available on * the scoop and input buffer. */ static rs_result rs_delta_s_scan(rs_job_t *job) { size_t this_len, avail_len; int is_ending; void *inptr; rs_result result; rs_job_check(job); avail_len = rs_scoop_total_avail(job); this_len = job->block_len; is_ending = job->stream->eof_in; /* Now, we have avail_len bytes, and we need to scan through them * looking for a match. We'll always end up emitting exactly one * command, either a literal or a copy, and after discovering that * we will skip over the appropriate number of bytes. */ if (avail_len == 0) { if (is_ending) { /* no more delta to do */ job->statefn = rs_delta_s_end; } return RS_BLOCKED; } /* must read at least one block, or give up */ if ((avail_len < job->block_len) && !is_ending) { /* we know we won't get it, but we have to try for a whole * block anyhow so that it gets into the scoop. */ rs_scoop_input(job, job->block_len); return RS_BLOCKED; } result = rs_scoop_readahead(job, avail_len, &inptr); if (result != RS_DONE) return result; return rs_delta_scan(job, avail_len, inptr); } /** * Scan for a matching block in the next \p avail_len bytes of input. * * If nonmatching data is found, then a LITERAL command will be put in * the tube immediately. If matching data is found, then its position * will be saved in the job, and the job state set up to write out a * COPY command after handling the literal. */ static rs_result rs_delta_scan(rs_job_t *job, rs_long_t avail_len, void *p) { rs_long_t match_where; int search_pos, end_pos; unsigned char *inptr = (unsigned char *) p; uint32_t s1 = job->weak_sig & 0xFFFF; uint32_t s2 = job->weak_sig >> 16; /* So, we have avail_len bytes of data, and we want to look * through it for a match at some point. It's OK if it's not at * the start of the available input data. If we're approaching * the end and can't get a match, then we just block and get more * later. */ /* FIXME: Perhaps we should be working in signed chars for the * rolling sum? */ if (job->stream->eof_in) end_pos = avail_len - 1; else end_pos = avail_len - job->block_len; for (search_pos = 0; search_pos <= end_pos; search_pos++) { size_t this_len = job->block_len; if (search_pos + this_len > avail_len) { this_len = avail_len - search_pos; rs_trace("block reduced to %d", this_len); } else if (job->have_weak_sig) { unsigned char a = inptr[search_pos + this_len - 1]; /* roll in the newly added byte, if any */ s1 += a + RS_CHAR_OFFSET; s2 += s1; job->weak_sig = (s1 & 0xffff) | (s2 << 16); } if (!job->have_weak_sig) { rs_trace("calculate weak sum from scratch"); job->weak_sig = rs_calc_weak_sum(inptr + search_pos, this_len); s1 = job->weak_sig & 0xFFFF; s2 = job->weak_sig >> 16; job->have_weak_sig = 1; } if (rs_roll_paranoia) { rs_weak_sum_t verify = rs_calc_weak_sum(inptr + search_pos, this_len); if (verify != job->weak_sig) { rs_fatal("mismatch between rolled sum %#x and check %#x", job->weak_sig, verify); } } if (rs_search_for_block(job->weak_sig, inptr + search_pos, this_len, job->signature, &job->stats, &match_where)) { /* So, we got a match. Cool. However, there may be * leading unmatched data that we need to flush. Thus we * set our statefn to be rs_delta_s_deferred_copy so that * we can write out the command later. */ rs_trace("matched %.0f bytes at %.0f!", (double) this_len, (double) match_where); job->basis_pos = match_where; job->basis_len = this_len; job->statefn = rs_delta_s_deferred_copy; job->have_weak_sig = 0; break; } else { /* advance by one; roll out the byte we just moved over. */ unsigned char a = inptr[search_pos]; unsigned char shift = a + RS_CHAR_OFFSET; s1 -= shift; s2 -= this_len * shift; job->weak_sig = (s1 & 0xffff) | (s2 << 16); } } if (search_pos > 0) { /* We may or may not have found a block, but we know we found * some literal data at the start of the buffer. Therefore, * we have to flush that out before we can continue on and * emit the copy command or keep searching. */ /* FIXME: At the moment, if you call with very short buffers, * then you will get a series of very short LITERAL commands. * Perhaps this is what you deserve, or perhaps we should try * to get more readahead and avoid that. */ /* There's some literal data at the start of this window which * we know is not in any block. */ rs_trace("got %d bytes of literal data", search_pos); rs_emit_literal_cmd(job, search_pos); rs_tube_copy(job, search_pos); } return RS_RUNNING; } static rs_result rs_delta_s_deferred_copy(rs_job_t *job) { if (!job->basis_len) { rs_log(RS_LOG_ERR, "somehow got zero basis_len"); return RS_INTERNAL_ERROR; } rs_emit_copy_cmd(job, job->basis_pos, job->basis_len); rs_scoop_advance(job, job->basis_len); job->statefn = rs_delta_s_scan; return RS_RUNNING; } /** * \brief State function that does a slack delta containing only * literal data to recreate the input. */ static rs_result rs_delta_s_slack(rs_job_t *job) { rs_buffers_t * const stream = job->stream; size_t avail = stream->avail_in; if (avail) { rs_trace("emit slack delta for %.0f available bytes", (double) avail); rs_emit_literal_cmd(job, avail); rs_tube_copy(job, avail); return RS_RUNNING; } else { if (rs_job_input_is_ending(job)) { job->statefn = rs_delta_s_end; return RS_RUNNING; } else { return RS_BLOCKED; } } } /** * State function for writing out the header of the encoding job. */ static rs_result rs_delta_s_header(rs_job_t *job) { rs_emit_delta_header(job); if (job->block_len) { if (!job->signature) { rs_error("no signature is loaded into the job"); return RS_PARAM_ERROR; } job->statefn = rs_delta_s_scan; } else { rs_trace("block length is zero for this delta; " "therefore using slack deltas"); job->statefn = rs_delta_s_slack; } return RS_RUNNING; } /** * Prepare to compute a streaming delta. */ rs_job_t *rs_delta_begin(rs_signature_t *sig) { rs_job_t *job; job = rs_job_new("delta", rs_delta_s_header); job->signature = sig; if ((job->block_len = sig->block_len) < 0) { rs_log(RS_LOG_ERR, "unreasonable block_len %d in signature", job->block_len); + rs_job_free(job); return NULL; } job->strong_sum_len = sig->strong_sum_len; if (job->strong_sum_len < 0 || job->strong_sum_len > RS_MD4_LENGTH) { rs_log(RS_LOG_ERR, "unreasonable strong_sum_len %d in signature", job->strong_sum_len); + rs_job_free(job); return NULL; } return job; } |