|
|
| version 1.74, 2002/08/01 11:41:12 | version 1.78, 2002/11/21 09:47:34 |
|---|---|
| Line 44 public: // Methoded | Line 44 public: // Methoded |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| class Measure_reader { | class Measure_reader { |
| public: | public: |
| enum { READ_CHUNK_SIZE=0x400*20 };// 20K | virtual size_t read(const void *&buf, size_t limit)=0; |
| typedef size_t(*Func)(void *& buf, size_t limit, void *info); | virtual void seek(long delta)=0; |
| }; | |
| Measure_reader(Func afunc, void *ainfo) : | class Measure_file_reader: public Measure_reader { |
| func(afunc), info(ainfo), | public: |
| chunk(0), offset(0), size(0) { | Measure_file_reader(Pool& apool, int af, const String& afile_name, const char *afname): |
| pool(apool), file_name(afile_name), fname(afname), f(af) { | |
| } | } |
| size_t read(void *&buf, size_t limit) { | /*override*/size_t read(const void *&abuf, size_t limit) { |
| if(offset+limit>size) // nothing left | if(limit==0) |
| if(offset==0 || limit==1) { // only one-byte continuations allowed | |
| size=(*func)(chunk, READ_CHUNK_SIZE, info); | |
| offset=0; | |
| } else | |
| return 0;// as if EOF | |
| if(!size) // EOF | |
| return 0; | return 0; |
| // something left | void *lbuf=pool.malloc(limit); |
| size_t read_size=min(offset+limit, size)-offset; | size_t read_size=(size_t)::read(f, lbuf, limit); abuf=lbuf; |
| buf=((unsigned char *)chunk)+offset; | if(ssize_t(read_size)<0 || read_size>limit) |
| offset+=read_size; | throw Exception(0, |
| &file_name, | |
| "measure failed: actually read %lu bytes count not in [0..%lu] valid range", | |
| read_size, limit); | |
| return read_size; | return read_size; |
| } | } |
| /*override*/void seek(long delta) { | |
| if(lseek(f, delta, SEEK_CUR)<0) | |
| throw Exception("file.seek", | |
| &file_name, | |
| "seek(delta=%ld) failed: %s (%d), actual filename '%s'", | |
| delta, strerror(errno), errno, fname); | |
| } | |
| private: | |
| Pool& pool; | |
| const String& file_name; const char *fname; | |
| int f; | |
| }; | |
| class Measure_buf_reader: public Measure_reader { | |
| public: | |
| Measure_buf_reader(const void *abuf, size_t asize, const String& afile_name): | |
| buf(abuf), size(asize), file_name(afile_name), offset(0) { | |
| } | |
| /*override*/size_t read(const void *&abuf, size_t limit) { | |
| size_t to_read=min(limit, size-offset); | |
| abuf=(const char*)buf+offset; | |
| offset+=to_read; | |
| return to_read; | |
| } | |
| /*override*/void seek(long delta) { | |
| size_t new_offset=offset+delta; | |
| if((ssize_t)new_offset<0 || new_offset>size) | |
| throw Exception("file.seek", | |
| &file_name, | |
| "seek(offset=%l) failed: out of buffer, new_offset>size (%l>%l) or new_offset<0", | |
| delta, new_offset, size); | |
| offset=new_offset; | |
| } | |
| private: | private: |
| Func func; | |
| void *info; | |
| void *chunk; | const void *buf; size_t size; |
| const String& file_name; | |
| size_t offset; | size_t offset; |
| size_t size; | |
| }; | }; |
| #endif | #endif |
| /// PNG file header | /// PNG file header |
| Line 116 struct JPG_Size_segment_body { | Line 153 struct JPG_Size_segment_body { |
| // | // |
| inline short x_endian_to_int(unsigned char L, unsigned char H) { | inline ushort x_endian_to_ushort(unsigned char L, unsigned char H) { |
| return(short)((H<<8) + L); | return(short)((H<<8) + L); |
| } | } |
| inline short big_endian_to_int(unsigned char b[2]) { | inline ushort big_endian_to_ushort(unsigned char b[2]) { |
| return x_endian_to_int(b[1], b[0]); | return x_endian_to_ushort(b[1], b[0]); |
| } | } |
| inline short little_endian_to_int(unsigned char b[2]) { | inline ushort little_endian_to_ushort(unsigned char b[2]) { |
| return x_endian_to_int(b[0], b[1]); | return x_endian_to_ushort(b[0], b[1]); |
| } | } |
| void measure_gif(Pool& pool, const String *origin_string, | void measure_gif(Pool& pool, const String *origin_string, |
| Measure_reader& reader, int& width, int& height) { | Measure_reader& reader, ushort& width, ushort& height) { |
| void *buf; | void *buf; |
| const int head_size=sizeof(GIF_Header); | const int head_size=sizeof(GIF_Header); |
| Line 144 void measure_gif(Pool& pool, const Strin | Line 181 void measure_gif(Pool& pool, const Strin |
| origin_string, | origin_string, |
| "not GIF file - wrong signature"); | "not GIF file - wrong signature"); |
| width=little_endian_to_int(head->width); | width=little_endian_to_ushort(head->width); |
| height=little_endian_to_int(head->height); | height=little_endian_to_ushort(head->height); |
| } | } |
| /// @test remove ugly mech in reader - 20K limit | /// @test remove ugly mech in reader - 20K limit |
| void measure_jpeg(Pool& pool, const String *origin_string, | void measure_jpeg(Pool& pool, const String *origin_string, |
| Measure_reader& reader, int& width, int& height) { | Measure_reader& reader, ushort& width, ushort& height) { |
| // JFIF format markers | // JFIF format markers |
| const unsigned char MARKER=0xFF; | const unsigned char MARKER=0xFF; |
| const unsigned char CODE_SIZE_FIRST=0xC0; | const unsigned char CODE_SIZE_FIRST=0xC0; |
| Line 187 void measure_jpeg(Pool& pool, const Stri | Line 224 void measure_jpeg(Pool& pool, const Stri |
| break; | break; |
| JPG_Size_segment_body *body=(JPG_Size_segment_body *)buf; | JPG_Size_segment_body *body=(JPG_Size_segment_body *)buf; |
| width=big_endian_to_int(body->width); | width=big_endian_to_ushort(body->width); |
| height=big_endian_to_int(body->height); | height=big_endian_to_ushort(body->height); |
| found=true; | found=true; |
| break; | break; |
| } else { | } else { |
| // Dummy read to skip over data | // Dummy read to skip over data |
| size_t limit=big_endian_to_int(head->length) - 2; | long offset=big_endian_to_ushort(head->length) - 2; |
| if(reader.read(buf, limit)<limit) | reader.seek(offset); |
| break; | |
| } | } |
| } | } |
| Line 206 void measure_jpeg(Pool& pool, const Stri | Line 242 void measure_jpeg(Pool& pool, const Stri |
| } | } |
| void measure_png(Pool& pool, const String *origin_string, | void measure_png(Pool& pool, const String *origin_string, |
| Measure_reader& reader, int& width, int& height) { | Measure_reader& reader, ushort& width, ushort& height) { |
| void *buf; | void *buf; |
| const int head_size=sizeof(PNG_Header); | const int head_size=sizeof(PNG_Header); |
| Line 221 void measure_png(Pool& pool, const Strin | Line 257 void measure_png(Pool& pool, const Strin |
| origin_string, | origin_string, |
| "not PNG file - wrong signature"); | "not PNG file - wrong signature"); |
| width=big_endian_to_int(head->width); | width=big_endian_to_ushort(head->width); |
| height=big_endian_to_int(head->height); | height=big_endian_to_ushort(head->height); |
| } | } |
| // measure center | // measure center |
| void measure(Pool& pool, const String& file_name, | void measure(Pool& pool, const String& file_name, |
| Measure_reader& reader, int& width, int& height) { | Measure_reader& reader, ushort& width, ushort& height) { |
| if(const char *cext=strrchr(file_name.cstr(String::UL_FILE_SPEC), '.')) { | if(const char *cext=strrchr(file_name.cstr(String::UL_FILE_SPEC), '.')) { |
| cext++; | cext++; |
| if(strcasecmp(cext, "GIF")==0) | if(strcasecmp(cext, "GIF")==0) |
| Line 247 void measure(Pool& pool, const String& f | Line 283 void measure(Pool& pool, const String& f |
| "can not determine image type - no file name extension"); | "can not determine image type - no file name extension"); |
| } | } |
| #ifndef DOXYGEN | // methods |
| struct Read_mem_info { | |
| unsigned char *ptr; | |
| unsigned char *eof; | |
| }; | |
| #endif | |
| static size_t read_mem(void*& buf, size_t limit, void *info) { | |
| Read_mem_info& rmi=*static_cast<Read_mem_info *>(info); | |
| buf=rmi.ptr; | |
| size_t read_size=min(limit, (size_t)(rmi.eof-rmi.ptr)); | |
| rmi.ptr+=read_size; | |
| return read_size; | |
| } | |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct Read_disk_info { | struct File_measure_action_info { |
| const String *file_spec; | ushort *width; |
| size_t offset; | ushort *height; |
| const String *file_name; | |
| }; | }; |
| #endif | #endif |
| static size_t read_disk(void*& buf, size_t limit, void *info) { | static void file_measure_action(Pool& pool, |
| Read_disk_info& rdi=*static_cast<Read_disk_info *>(info); | int f, |
| Pool& pool=rdi.file_spec->pool(); | const String& file_spec, const char *fname, bool as_text, |
| void *context) { | |
| size_t read_size; | File_measure_action_info& info=*static_cast<File_measure_action_info *>(context); |
| file_read(pool, *rdi.file_spec, | |
| buf, read_size, | |
| false/*as_text*/, | |
| true/*fail_on_read_problem*/, | |
| rdi.offset, limit); | |
| rdi.offset+=read_size; | Measure_file_reader reader(pool, f, *info.file_name, fname); |
| return read_size; | measure(pool, *info.file_name, reader, *info.width, *info.height); |
| } | } |
| // methods | |
| static void _measure(Request& r, const String& method_name, MethodParams *params) { | static void _measure(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| Value& data=params->as_no_junction(0, "data must not be code"); | Value& data=params->as_no_junction(0, "data must not be code"); |
| void *info;Measure_reader::Func read_func; | ushort width=0; |
| Read_mem_info read_mem_info; | ushort height=0; |
| Read_disk_info read_disk_info; | |
| const String *file_name; | const String *file_name; |
| if(data.is_string()) { | if(file_name=data.get_string()) { |
| file_name=data.get_string(); | File_measure_action_info info={&width, &height, file_name}; |
| read_disk_info.file_spec=&r.absolute(*file_name); | file_read_action_under_lock(pool, r.absolute(*file_name), |
| read_disk_info.offset=0; | "measure", file_measure_action, &info); |
| info=&read_disk_info;read_func=read_disk; | |
| } else { | } else { |
| const VFile& vfile=*data.as_vfile(); | const VFile& vfile=*data.as_vfile(); |
| file_name=&static_cast<Value *>(vfile.fields().get(*name_name))->as_string(); | file_name=&static_cast<Value *>(vfile.fields().get(*name_name))->as_string(); |
| read_mem_info.ptr=(unsigned char *)vfile.value_ptr(); | Measure_buf_reader reader( |
| read_mem_info.eof=read_mem_info.ptr+vfile.value_size(); | vfile.value_ptr(), |
| info=&read_mem_info;read_func=read_mem; | vfile.value_size(), |
| *file_name | |
| ); | |
| measure(pool, *file_name, reader, width, height); | |
| } | } |
| Measure_reader reader(read_func, info); | static_cast<VImage *>(r.get_self())->set(file_name, width, height); |
| int width, height; | |
| measure(pool, *file_name, reader, width, height); | |
| static_cast<VImage *>(r.self)->set(file_name, width, height); | |
| } | } |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| Line 338 static void _html(Request& r, const Stri | Line 353 static void _html(Request& r, const Stri |
| String tag(pool); | String tag(pool); |
| tag << "<img"; | tag << "<img"; |
| const Hash& fields=static_cast<VImage *>(r.self)->fields(); | const Hash& fields=static_cast<VImage *>(r.get_self())->fields(); |
| Hash *attribs=0; | Hash *attribs=0; |
| if(params->size()) { | if(params->size()) { |
| Line 394 static void _load(Request& r, const Stri | Line 409 static void _load(Request& r, const Stri |
| gdImage& image=*load(r, method_name, file_name); | gdImage& image=*load(r, method_name, file_name); |
| int width=image.SX(); | int width=image.SX(); |
| int height=image.SY(); | int height=image.SY(); |
| static_cast<VImage *>(r.self)->set(&file_name, width, height, &image); | static_cast<VImage *>(r.get_self())->set(&file_name, width, height, &image); |
| } | } |
| static void _create(Request& r, const String& method_name, MethodParams *params) { | static void _create(Request& r, const String& method_name, MethodParams *params) { |
| Line 408 static void _create(Request& r, const St | Line 423 static void _create(Request& r, const St |
| gdImage& image=*new(pool) gdImage(pool); | gdImage& image=*new(pool) gdImage(pool); |
| image.Create(width, height); | image.Create(width, height); |
| image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value)); | image.FilledRectangle(0, 0, width-1, height-1, image.Color(bgcolor_value)); |
| static_cast<VImage *>(r.self)->set(0, width, height, &image); | static_cast<VImage *>(r.get_self())->set(0, width, height, &image); |
| } | } |
| static void _gif(Request& r, const String& method_name, MethodParams *params) { | static void _gif(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 435 static void _gif(Request& r, const Strin | Line 450 static void _gif(Request& r, const Strin |
| static void _line(Request& r, const String& method_name, MethodParams *params) { | static void _line(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 452 static void _line(Request& r, const Stri | Line 467 static void _line(Request& r, const Stri |
| static void _fill(Request& r, const String& method_name, MethodParams *params) { | static void _fill(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 467 static void _fill(Request& r, const Stri | Line 482 static void _fill(Request& r, const Stri |
| static void _rectangle(Request& r, const String& method_name, MethodParams *params) { | static void _rectangle(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 484 static void _rectangle(Request& r, const | Line 499 static void _rectangle(Request& r, const |
| static void _bar(Request& r, const String& method_name, MethodParams *params) { | static void _bar(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 511 static void add_point(Array::Item *value | Line 526 static void add_point(Array::Item *value |
| static void _replace(Request& r, const String& method_name, MethodParams *params) { | static void _replace(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 534 static void _replace(Request& r, const S | Line 549 static void _replace(Request& r, const S |
| static void _polyline(Request& r, const String& method_name, MethodParams *params) { | static void _polyline(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 557 static void _polyline(Request& r, const | Line 572 static void _polyline(Request& r, const |
| static void _polygon(Request& r, const String& method_name, MethodParams *params) { | static void _polygon(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 579 static void _polygon(Request& r, const S | Line 594 static void _polygon(Request& r, const S |
| static void _polybar(Request& r, const String& method_name, MethodParams *params) { | static void _polybar(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 686 static void _font(Request& r, const Stri | Line 701 static void _font(Request& r, const Stri |
| &method_name, | &method_name, |
| "alphabet must not be empty"); | "alphabet must not be empty"); |
| static_cast<VImage *>(r.self)->font=new(pool) Font(pool, | static_cast<VImage *>(r.get_self())->font=new(pool) Font(pool, |
| alphabet, | alphabet, |
| image, | image, |
| image.SY() / alphabet.size(), monospace_width, spacebar_width); | image.SY() / alphabet.size(), monospace_width, spacebar_width); |
| Line 699 static void _text(Request& r, const Stri | Line 714 static void _text(Request& r, const Stri |
| int y=params->as_int(1, "y must be int", r); | int y=params->as_int(1, "y must be int", r); |
| const String& s=params->as_string(2, "text must not be code"); | const String& s=params->as_string(2, "text must not be code"); |
| VImage& vimage=*static_cast<VImage *>(r.self); | VImage& vimage=*static_cast<VImage *>(r.get_self()); |
| if(vimage.image) | if(vimage.image) |
| if(vimage.font) | if(vimage.font) |
| vimage.font->string_display(*vimage.image, x, y, s); | vimage.font->string_display(*vimage.image, x, y, s); |
| Line 718 static void _length(Request& r, const St | Line 733 static void _length(Request& r, const St |
| const String& s=params->as_string(0, "text must not be code"); | const String& s=params->as_string(0, "text must not be code"); |
| VImage& vimage=*static_cast<VImage *>(r.self); | VImage& vimage=*static_cast<VImage *>(r.get_self()); |
| if(vimage.image) | if(vimage.image) |
| if(vimage.font) { | if(vimage.font) { |
| r.write_no_lang(*new(pool) VInt(pool, vimage.font->string_width(s))); | r.write_no_lang(*new(pool) VInt(pool, vimage.font->string_width(s))); |
| Line 735 static void _length(Request& r, const St | Line 750 static void _length(Request& r, const St |
| static void _arc(Request& r, const String& method_name, MethodParams *params) { | static void _arc(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 754 static void _arc(Request& r, const Strin | Line 769 static void _arc(Request& r, const Strin |
| static void _sector(Request& r, const String& method_name, MethodParams *params) { | static void _sector(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 773 static void _sector(Request& r, const St | Line 788 static void _sector(Request& r, const St |
| static void _circle(Request& r, const String& method_name, MethodParams *params) { | static void _circle(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *image=static_cast<VImage *>(r.self)->image; | gdImage *image=static_cast<VImage *>(r.get_self())->image; |
| if(!image) | if(!image) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |
| Line 792 static void _circle(Request& r, const St | Line 807 static void _circle(Request& r, const St |
| gdImage& as_image(Pool& pool, const String& method_name, MethodParams *params, | gdImage& as_image(Pool& pool, const String& method_name, MethodParams *params, |
| int index, const char *msg) { | int index, const char *msg) { |
| Value& value=params->as_no_junction(index, msg); | gdImage *src=0; |
| if(strcmp(value.type(), VIMAGE_TYPE)!=0) | Value& value=params->as_no_junction(index, msg); |
| throw Exception("parser.runtime", | |
| &method_name, | |
| msg); | |
| gdImage *src=static_cast<VImage *>(&value)->image; | if(Value *vimage=value.as(VIMAGE_TYPE, false)) { |
| if(!src) | src=static_cast<VImage *>(vimage)->image; |
| if(!src) | |
| throw Exception("parser.runtime", | |
| &method_name, | |
| msg); | |
| } else | |
| throw Exception("parser.runtime", | throw Exception("parser.runtime", |
| &method_name, | &method_name, |
| msg); | msg); |
| Line 811 gdImage& as_image(Pool& pool, const Stri | Line 828 gdImage& as_image(Pool& pool, const Stri |
| static void _copy(Request& r, const String& method_name, MethodParams *params) { | static void _copy(Request& r, const String& method_name, MethodParams *params) { |
| Pool& pool=r.pool(); | Pool& pool=r.pool(); |
| gdImage *dest=static_cast<VImage *>(r.self)->image; | gdImage *dest=static_cast<VImage *>(r.get_self())->image; |
| if(!dest) | if(!dest) |
| throw Exception(0, | throw Exception(0, |
| &method_name, | &method_name, |