From dadc1c246223872f6e036c38d99fd412abb64fd3 Mon Sep 17 00:00:00 2001 From: huahaiyan <3686255842@qq.com> Date: Tue, 6 Feb 2024 14:19:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + NPlotter.pro | 141 + README.md | 92 + addmachinedialog.cpp | 70 + addmachinedialog.h | 33 + addmachinedialog.ui | 97 + bmp/bwbmp.cpp | 662 +++ bmp/bwbmp.h | 119 + bmp/creatprintbmp.cpp | 130 + bmp/creatprintbmp.h | 41 + datafile/dxf.zip | Bin 0 -> 59343 bytes datafile/dxf/dxfhelper.cpp | 520 ++ datafile/dxf/dxfhelper.h | 114 + datafile/dxf/dxflib/dl_attributes.h | 237 + datafile/dxf/dxflib/dl_codes.h | 546 ++ datafile/dxf/dxflib/dl_creationadapter.h | 138 + datafile/dxf/dxflib/dl_creationinterface.h | 369 ++ datafile/dxf/dxflib/dl_dxf.cpp | 5332 ++++++++++++++++++++ datafile/dxf/dxflib/dl_dxf.h | 529 ++ datafile/dxf/dxflib/dl_entities.h | 1813 +++++++ datafile/dxf/dxflib/dl_exception.h | 55 + datafile/dxf/dxflib/dl_extrusion.h | 143 + datafile/dxf/dxflib/dl_global.h | 13 + datafile/dxf/dxflib/dl_writer.h | 654 +++ datafile/dxf/dxflib/dl_writer_ascii.cpp | 156 + datafile/dxf/dxflib/dl_writer_ascii.h | 74 + datafile/dxf/dxfreader.cpp | 379 ++ datafile/dxf/dxfreader.h | 112 + datafile/hpgl.7z | Bin 0 -> 37050 bytes datafile/hpgl/importhpgl.cpp | 2430 +++++++++ datafile/hpgl/importhpgl.h | 268 + datafile/hpgl/marker.cpp | 261 + datafile/hpgl/marker.h | 420 ++ datafile/hpgl/plotbitmap.cpp | 89 + datafile/hpgl/plotbitmap.h | 65 + datafile/hpgl/typedef.h | 107 + datafile/hpgl/vectorfont.cpp | 918 ++++ datafile/hpgl/vectorfont.h | 132 + datafile/hpgl/vectorsqrt.cpp | 4501 +++++++++++++++++ datafile/hpgl/vectorsqrt.h | 135 + datafile/qrencode/bitstream.c | 231 + datafile/qrencode/bitstream.h | 43 + datafile/qrencode/config.h | 102 + datafile/qrencode/mask.c | 357 ++ datafile/qrencode/mask.h | 38 + datafile/qrencode/mmask.c | 177 + datafile/qrencode/mmask.h | 34 + datafile/qrencode/mqrspec.c | 232 + datafile/qrencode/mqrspec.h | 150 + datafile/qrencode/qrenc.c | 1453 ++++++ datafile/qrencode/qrencode.c | 938 ++++ datafile/qrencode/qrencode.h | 568 +++ datafile/qrencode/qrencode_inner.h | 88 + datafile/qrencode/qrinput.c | 1639 ++++++ datafile/qrencode/qrinput.h | 124 + datafile/qrencode/qrspec.c | 514 ++ datafile/qrencode/qrspec.h | 174 + datafile/qrencode/rsecc.c | 149 + datafile/qrencode/rsecc.h | 31 + datafile/qrencode/split.c | 323 ++ datafile/qrencode/split.h | 47 + datafile/view/mygraphicsitem.cpp | 261 + datafile/view/mygraphicsitem.h | 54 + datafile/view/mygraphicsscene.cpp | 85 + datafile/view/mygraphicsscene.h | 38 + datafile/view/mygraphicsview.cpp | 240 + datafile/view/mygraphicsview.h | 50 + datafile/zip/unzip.cpp | 4334 ++++++++++++++++ datafile/zip/unzip.h | 226 + datafile/zip/zip.cpp | 2990 +++++++++++ datafile/zip/zip.h | 214 + datafile/zip/zipreader.cpp | 89 + datafile/zip/zipreader.h | 30 + datafile/zip/zipwriter.cpp | 70 + datafile/zip/zipwriter.h | 27 + drawingsetdialog.cpp | 16 + drawingsetdialog.h | 22 + drawingsetdialog.ui | 356 ++ historydialog.cpp | 16 + historydialog.h | 22 + historydialog.ui | 68 + include/qrencode.h | 568 +++ lib/libqrencode.a | Bin 0 -> 51502 bytes machine/bmp/bwbmp.cpp | 604 +++ machine/bmp/bwbmp.h | 73 + machine/bmp/creatprintbmp.cpp | 741 +++ machine/bmp/creatprintbmp.h | 94 + machine/comm/comm.cpp | 438 ++ machine/comm/comm.h | 205 + machine/comm/crc16.cpp | 159 + machine/comm/crc16.h | 60 + machine/comm/crc32.cpp | 74 + machine/comm/crc32.h | 33 + machine/comm/protocol.h | 466 ++ machine/comm/typedef.h | 16 + machine/machine.cpp | 1061 ++++ machine/machine.h | 140 + machine/printinfo/mcfiles.h | 232 + machine/tcp/qbindtcpsocket.cpp | 186 + machine/tcp/qbindtcpsocket.h | 53 + machine/tcp/tcpclient.cpp | 460 ++ machine/tcp/tcpclient.h | 97 + machine/tcp/tcpserver.cpp | 123 + machine/tcp/tcpserver.h | 55 + main.cpp | 88 + main.h | 26 + mainwidget.ui | 24 + mainwindow.cpp | 1499 ++++++ mainwindow.h | 157 + mainwindow.ui | 514 ++ plottersetdialog.cpp | 16 + plottersetdialog.h | 22 + plottersetdialog.ui | 798 +++ printinfodialog.cpp | 119 + printinfodialog.h | 40 + printinfodialog.ui | 309 ++ printnumbersetdialog.cpp | 47 + printnumbersetdialog.h | 30 + printnumbersetdialog.ui | 84 + printviewwindow.cpp | 109 + printviewwindow.h | 51 + printviewwindow.ui | 230 + res.qrc | 20 + resources/ErrorX.bmp | Bin 0 -> 1846 bytes resources/ErrorY.bmp | Bin 0 -> 1846 bytes resources/OpenFile.bmp | Bin 0 -> 1784 bytes resources/OpenImage.png | Bin 0 -> 2083 bytes resources/SetPara.bmp | Bin 0 -> 1784 bytes resources/delete.bmp | Bin 0 -> 1784 bytes resources/down.bmp | Bin 0 -> 3944 bytes resources/down_gap.bmp | Bin 0 -> 246 bytes resources/edit.bmp | Bin 0 -> 1784 bytes resources/mark_gap.bmp | Bin 0 -> 246 bytes resources/page_cx.bmp | Bin 0 -> 598 bytes resources/page_cy.bmp | Bin 0 -> 598 bytes resources/pause.bmp | Bin 0 -> 3944 bytes resources/right_ga.bmp | Bin 0 -> 246 bytes resources/start.bmp | Bin 0 -> 3944 bytes resources/up.bmp | Bin 0 -> 3944 bytes startsetdialog.cpp | 50 + startsetdialog.h | 31 + startsetdialog.ui | 84 + 142 files changed, 48805 insertions(+) create mode 100644 .gitignore create mode 100644 NPlotter.pro create mode 100644 README.md create mode 100644 addmachinedialog.cpp create mode 100644 addmachinedialog.h create mode 100644 addmachinedialog.ui create mode 100644 bmp/bwbmp.cpp create mode 100644 bmp/bwbmp.h create mode 100644 bmp/creatprintbmp.cpp create mode 100644 bmp/creatprintbmp.h create mode 100644 datafile/dxf.zip create mode 100644 datafile/dxf/dxfhelper.cpp create mode 100644 datafile/dxf/dxfhelper.h create mode 100644 datafile/dxf/dxflib/dl_attributes.h create mode 100644 datafile/dxf/dxflib/dl_codes.h create mode 100644 datafile/dxf/dxflib/dl_creationadapter.h create mode 100644 datafile/dxf/dxflib/dl_creationinterface.h create mode 100644 datafile/dxf/dxflib/dl_dxf.cpp create mode 100644 datafile/dxf/dxflib/dl_dxf.h create mode 100644 datafile/dxf/dxflib/dl_entities.h create mode 100644 datafile/dxf/dxflib/dl_exception.h create mode 100644 datafile/dxf/dxflib/dl_extrusion.h create mode 100644 datafile/dxf/dxflib/dl_global.h create mode 100644 datafile/dxf/dxflib/dl_writer.h create mode 100644 datafile/dxf/dxflib/dl_writer_ascii.cpp create mode 100644 datafile/dxf/dxflib/dl_writer_ascii.h create mode 100644 datafile/dxf/dxfreader.cpp create mode 100644 datafile/dxf/dxfreader.h create mode 100644 datafile/hpgl.7z create mode 100644 datafile/hpgl/importhpgl.cpp create mode 100644 datafile/hpgl/importhpgl.h create mode 100644 datafile/hpgl/marker.cpp create mode 100644 datafile/hpgl/marker.h create mode 100644 datafile/hpgl/plotbitmap.cpp create mode 100644 datafile/hpgl/plotbitmap.h create mode 100644 datafile/hpgl/typedef.h create mode 100644 datafile/hpgl/vectorfont.cpp create mode 100644 datafile/hpgl/vectorfont.h create mode 100644 datafile/hpgl/vectorsqrt.cpp create mode 100644 datafile/hpgl/vectorsqrt.h create mode 100644 datafile/qrencode/bitstream.c create mode 100644 datafile/qrencode/bitstream.h create mode 100644 datafile/qrencode/config.h create mode 100644 datafile/qrencode/mask.c create mode 100644 datafile/qrencode/mask.h create mode 100644 datafile/qrencode/mmask.c create mode 100644 datafile/qrencode/mmask.h create mode 100644 datafile/qrencode/mqrspec.c create mode 100644 datafile/qrencode/mqrspec.h create mode 100644 datafile/qrencode/qrenc.c create mode 100644 datafile/qrencode/qrencode.c create mode 100644 datafile/qrencode/qrencode.h create mode 100644 datafile/qrencode/qrencode_inner.h create mode 100644 datafile/qrencode/qrinput.c create mode 100644 datafile/qrencode/qrinput.h create mode 100644 datafile/qrencode/qrspec.c create mode 100644 datafile/qrencode/qrspec.h create mode 100644 datafile/qrencode/rsecc.c create mode 100644 datafile/qrencode/rsecc.h create mode 100644 datafile/qrencode/split.c create mode 100644 datafile/qrencode/split.h create mode 100644 datafile/view/mygraphicsitem.cpp create mode 100644 datafile/view/mygraphicsitem.h create mode 100644 datafile/view/mygraphicsscene.cpp create mode 100644 datafile/view/mygraphicsscene.h create mode 100644 datafile/view/mygraphicsview.cpp create mode 100644 datafile/view/mygraphicsview.h create mode 100644 datafile/zip/unzip.cpp create mode 100644 datafile/zip/unzip.h create mode 100644 datafile/zip/zip.cpp create mode 100644 datafile/zip/zip.h create mode 100644 datafile/zip/zipreader.cpp create mode 100644 datafile/zip/zipreader.h create mode 100644 datafile/zip/zipwriter.cpp create mode 100644 datafile/zip/zipwriter.h create mode 100644 drawingsetdialog.cpp create mode 100644 drawingsetdialog.h create mode 100644 drawingsetdialog.ui create mode 100644 historydialog.cpp create mode 100644 historydialog.h create mode 100644 historydialog.ui create mode 100644 include/qrencode.h create mode 100644 lib/libqrencode.a create mode 100644 machine/bmp/bwbmp.cpp create mode 100644 machine/bmp/bwbmp.h create mode 100644 machine/bmp/creatprintbmp.cpp create mode 100644 machine/bmp/creatprintbmp.h create mode 100644 machine/comm/comm.cpp create mode 100644 machine/comm/comm.h create mode 100644 machine/comm/crc16.cpp create mode 100644 machine/comm/crc16.h create mode 100644 machine/comm/crc32.cpp create mode 100644 machine/comm/crc32.h create mode 100644 machine/comm/protocol.h create mode 100644 machine/comm/typedef.h create mode 100644 machine/machine.cpp create mode 100644 machine/machine.h create mode 100644 machine/printinfo/mcfiles.h create mode 100644 machine/tcp/qbindtcpsocket.cpp create mode 100644 machine/tcp/qbindtcpsocket.h create mode 100644 machine/tcp/tcpclient.cpp create mode 100644 machine/tcp/tcpclient.h create mode 100644 machine/tcp/tcpserver.cpp create mode 100644 machine/tcp/tcpserver.h create mode 100644 main.cpp create mode 100644 main.h create mode 100644 mainwidget.ui create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 plottersetdialog.cpp create mode 100644 plottersetdialog.h create mode 100644 plottersetdialog.ui create mode 100644 printinfodialog.cpp create mode 100644 printinfodialog.h create mode 100644 printinfodialog.ui create mode 100644 printnumbersetdialog.cpp create mode 100644 printnumbersetdialog.h create mode 100644 printnumbersetdialog.ui create mode 100644 printviewwindow.cpp create mode 100644 printviewwindow.h create mode 100644 printviewwindow.ui create mode 100644 res.qrc create mode 100644 resources/ErrorX.bmp create mode 100644 resources/ErrorY.bmp create mode 100644 resources/OpenFile.bmp create mode 100644 resources/OpenImage.png create mode 100644 resources/SetPara.bmp create mode 100644 resources/delete.bmp create mode 100644 resources/down.bmp create mode 100644 resources/down_gap.bmp create mode 100644 resources/edit.bmp create mode 100644 resources/mark_gap.bmp create mode 100644 resources/page_cx.bmp create mode 100644 resources/page_cy.bmp create mode 100644 resources/pause.bmp create mode 100644 resources/right_ga.bmp create mode 100644 resources/start.bmp create mode 100644 resources/up.bmp create mode 100644 startsetdialog.cpp create mode 100644 startsetdialog.h create mode 100644 startsetdialog.ui diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19b790c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.d0fd913 +*.user.* +boost/ +spline_library/ diff --git a/NPlotter.pro b/NPlotter.pro new file mode 100644 index 0000000..d6734ae --- /dev/null +++ b/NPlotter.pro @@ -0,0 +1,141 @@ +#------------------------------------------------- +# +# Project created by Qt5.9.1 2022-10-24T09:06:36 +# created by HUAHAIYAN +#------------------------------------------------- + +TEMPLATE = app + +TARGET = NPotter + +#INCLUDEPATH +=$$PWD/../boost/ +#INCLUDEPATH +=$$PWD/../spline_library/ + +CONFIG += c++11 + +QT += core gui network +QT += serialport +QT += svg +QT += concurrent testlib #将类中的函数移到线程中 + + #用于zip的压缩和解压,因为qt自带的zip是私有的,所以工程会报警告,若要消除警告可尝试第三方的zip库 +QT += gui-private + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +OBJECTS_DIR += obj +MOC_DIR += moc +UI_DIR += forms +RCC_DIR += rccs + +DEFINES += HAVE_CONFIG_H + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + printviewwindow.cpp \ + datafile/hpgl/importhpgl.cpp \ + datafile/hpgl/marker.cpp \ + datafile/hpgl/vectorfont.cpp \ + datafile/view/mygraphicsitem.cpp \ + datafile/view/mygraphicsscene.cpp \ + datafile/view/mygraphicsview.cpp \ + printnumbersetdialog.cpp \ + drawingsetdialog.cpp \ + historydialog.cpp \ + plottersetdialog.cpp \ + startsetdialog.cpp \ + machine/machine.cpp \ + datafile/hpgl/plotbitmap.cpp \ + datafile/qrencode/bitstream.c \ + datafile/qrencode/mask.c \ + datafile/qrencode/mmask.c \ + datafile/qrencode/mqrspec.c \ + datafile/qrencode/qrencode.c \ + datafile/qrencode/qrinput.c \ + datafile/qrencode/qrspec.c \ + datafile/qrencode/rsecc.c \ + datafile/qrencode/split.c \ + machine/comm/comm.cpp \ + machine/comm/crc16.cpp \ + machine/comm/crc32.cpp \ + printinfodialog.cpp \ + datafile/dxf/dxfhelper.cpp \ + datafile/dxf/dxfreader.cpp \ + datafile/dxf/dxflib/dl_dxf.cpp \ + datafile/dxf/dxflib/dl_writer_ascii.cpp \ + addmachinedialog.cpp \ + machine/bmp/bwbmp.cpp \ + machine/bmp/creatprintbmp.cpp \ + machine/tcp/qbindtcpsocket.cpp \ + machine/tcp/tcpclient.cpp + +FORMS += \ + mainwidget.ui \ + mainwindow.ui \ + printviewwindow.ui \ + printnumbersetdialog.ui \ + drawingsetdialog.ui \ + historydialog.ui \ + plottersetdialog.ui \ + startsetdialog.ui \ + printinfodialog.ui \ + addmachinedialog.ui + +HEADERS += \ + main.h \ + mainwindow.h \ + printviewwindow.h \ + datafile/hpgl/importhpgl.h \ + datafile/hpgl/marker.h \ + datafile/hpgl/vectorfont.h \ + datafile/view/mygraphicsitem.h \ + datafile/view/mygraphicsscene.h \ + datafile/view/mygraphicsview.h \ + printnumbersetdialog.h \ + drawingsetdialog.h \ + historydialog.h \ + plottersetdialog.h \ + startsetdialog.h \ + datafile/hpgl/typedef.h \ + machine/machine.h \ + datafile/hpgl/plotbitmap.h \ + datafile/qrencode/bitstream.h \ + datafile/qrencode/config.h \ + datafile/qrencode/mask.h \ + datafile/qrencode/mmask.h \ + datafile/qrencode/mqrspec.h \ + datafile/qrencode/qrencode.h \ + datafile/qrencode/qrencode_inner.h \ + datafile/qrencode/qrinput.h \ + datafile/qrencode/qrspec.h \ + datafile/qrencode/rsecc.h \ + datafile/qrencode/split.h \ + machine/comm/protocol.h \ + machine/comm/comm.h \ + machine/comm/typedef.h \ + machine/comm/crc16.h \ + machine/comm/crc32.h \ + printinfodialog.h \ + datafile/dxf/dxfhelper.h \ + datafile/dxf/dxfreader.h \ + datafile/dxf/dxflib/dl_attributes.h \ + datafile/dxf/dxflib/dl_codes.h \ + datafile/dxf/dxflib/dl_creationadapter.h \ + datafile/dxf/dxflib/dl_creationinterface.h \ + datafile/dxf/dxflib/dl_dxf.h \ + datafile/dxf/dxflib/dl_entities.h \ + datafile/dxf/dxflib/dl_exception.h \ + datafile/dxf/dxflib/dl_extrusion.h \ + datafile/dxf/dxflib/dl_global.h \ + datafile/dxf/dxflib/dl_writer.h \ + datafile/dxf/dxflib/dl_writer_ascii.h \ + addmachinedialog.h \ + machine/bmp/bwbmp.h \ + machine/bmp/creatprintbmp.h \ + machine/tcp/qbindtcpsocket.h \ + machine/tcp/tcpclient.h \ + machine/printinfo/mcfiles.h + +RESOURCES += \ + res.qrc diff --git a/README.md b/README.md new file mode 100644 index 0000000..68fec35 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# NPlotter + + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin http://192.168.2.195:8099/hmi/plotter/nplotter.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +- [ ] [Set up project integrations](http://192.168.2.195:8099/hmi/plotter/nplotter/-/settings/integrations) + +## Collaborate with your team + +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/addmachinedialog.cpp b/addmachinedialog.cpp new file mode 100644 index 0000000..1ea5829 --- /dev/null +++ b/addmachinedialog.cpp @@ -0,0 +1,70 @@ +#include "addmachinedialog.h" +#include "ui_addmachinedialog.h" + +AddMachineDialog::AddMachineDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AddMachineDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + + QRegExp ipExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"); + ui->lineEdit_ip->setValidator(new QRegExpValidator(ipExp, ui->lineEdit_ip)); +} + +AddMachineDialog::~AddMachineDialog() +{ + delete ui; +} + +void AddMachineDialog::on_pushButton_ok_clicked() +{ + m_mcIp = ui->lineEdit_ip->text(); + m_mcName = ui->lineEdit_name->text(); + + bool bl = true; + if(m_mcIp.isEmpty()) + { + bl = false; + } + QStringList list = m_mcIp.split('.'); + if(list.size() != 4) + { + bl = false; + } + for(const auto& num : list) + { + bool ok = false; + int temp = num.toInt(&ok); + if(!ok || temp < 0 || temp > 255) + { + bl = false; + } + } + + if(bl == false) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Please enter the correct IP!"),//请输入正确的IP! + QMessageBox::Ok); + return; + } + + if(m_mcName.length() <= 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Please enter the correct machine name!"),//请输入正确的机器名称! + QMessageBox::Ok); + return; + } + + done(1); +} + +void AddMachineDialog::on_pushButton_cancel_clicked() +{ + done(0); +} diff --git a/addmachinedialog.h b/addmachinedialog.h new file mode 100644 index 0000000..fddffd9 --- /dev/null +++ b/addmachinedialog.h @@ -0,0 +1,33 @@ +#ifndef ADDMACHINEDIALOG_H +#define ADDMACHINEDIALOG_H + +#include +#include + +namespace Ui { +class AddMachineDialog; +} + +class AddMachineDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddMachineDialog(QWidget *parent = 0); + ~AddMachineDialog(); + +public: + inline QString getMcIp(){return m_mcIp;} + inline QString getMcName(){return m_mcName;} + +private slots: + void on_pushButton_ok_clicked(); + void on_pushButton_cancel_clicked(); + +private: + Ui::AddMachineDialog *ui; + QString m_mcIp; + QString m_mcName; +}; + +#endif // ADDMACHINEDIALOG_H diff --git a/addmachinedialog.ui b/addmachinedialog.ui new file mode 100644 index 0000000..0adeddd --- /dev/null +++ b/addmachinedialog.ui @@ -0,0 +1,97 @@ + + + AddMachineDialog + + + + 0 + 0 + 338 + 153 + + + + Dialog + + + + + 190 + 110 + 60 + 26 + + + + Ok + + + + + + 260 + 110 + 60 + 26 + + + + Cancel + + + + + + 50 + 40 + 31 + 16 + + + + IP: + + + + + + 90 + 40 + 191 + 20 + + + + + + + + + + 50 + 70 + 31 + 16 + + + + Name: + + + + + + 90 + 70 + 191 + 20 + + + + + + + + + + diff --git a/bmp/bwbmp.cpp b/bmp/bwbmp.cpp new file mode 100644 index 0000000..8fcc463 --- /dev/null +++ b/bmp/bwbmp.cpp @@ -0,0 +1,662 @@ +#include "bwbmp.h" +#include + +#include + + +BWBmp::BWBmp() +{ + +} + +int BWBmp::LoadBiBmp(QString filename) +{ + m_bwDdat.clear(); + m_prDdat.clear(); + + QFile file(filename); + int rslt = file.open(QFile::ReadOnly); + if (rslt == 0) + { + qDebug() << "open file error" << filename; + return -1; + } + + m_bwDdat = file.readAll(); + if (m_bwDdat.size() <= (int)sizeof(BitmapHead)) + { + m_bwDdat.clear(); + file.close(); + + qDebug() << "file size error, size=" << m_bwDdat.size(); + return -2; + } + + BitmapHead * pHead = (BitmapHead *)(m_bwDdat.data()); + + if ( (pHead->identifier != 0x4d42) || + (pHead->bitDatOffset != 0x3E) || + (pHead->biSize != 0x28) || + (pHead->biPlanes != 0x01) || + (pHead->biBitPerPixel != 0x01) || + (pHead->biCompression != 0x00) || + 0 ) + { + m_bwDdat.clear(); + file.close(); + + qDebug() << "not bi bmp"; + return -3; + } + + file.close(); + return 0; +} + + +int BWBmp::SavePrBmp(QString filename) +{ + QFile file(filename); + int rslt = file.open(QFile::ReadWrite | QFile::Truncate); + if (rslt == 0) + { + qDebug() << "open file error" << filename; + return -1; + } + + file.write(m_prDdat); + file.close(); + + return 0; +} + +int BWBmp::Compress(int idx, int dir) +{ + /* + 为了减少喷墨绘图仪的数据传输量,对黑白位图数据进行压缩。 + 压缩算法如下: + + 每个墨盒的位图数据宽度为300像素,高度不确定 + + 每个字节分为两段 + 用属性+值 的方式表示 + __________________________________________________ + | bit7 bit6 | bit5 bit4 bit3 bit2 bit1 bit0 | + -------------------------------------------------- + | 属性 | 值 | + -------------------------------------------------- + | 0 0 | 原始数据 | + -------------------------------------------------- + | 0 1 | 连续数据1的个数 | + -------------------------------------------------- + | 1 0 | 连续10个数据0的个数 | + -------------------------------------------------- + | 1 1 | 连续数据0的个数 | + -------------------------------------------------- + */ + + if (dir < 0) + { + dir = -1; + } + else + { + dir = 1; + } + + m_prDdat.clear(); + if (m_bwDdat.isEmpty() == 1) + { + qDebug() << "bit dat empty"; + return -1; + } + + QByteArray tmppr; + tmppr.clear(); + + BitmapHead * pHead = (BitmapHead *)(m_bwDdat.data()); + + int width = pHead->biWidth; + int height = pHead->biHeight; + int widthBytes = (int)((width + 31) / 32) * 4; + + if (widthBytes <= 0 || height < 1 || width > 0x1000000) + { + qDebug() << "bit dat error"; + return -2; + } + + const unsigned char * pBitDatBeg = (unsigned char *)(m_bwDdat.data() + pHead->bitDatOffset); + + const unsigned char * pTmpDat; + + if (dir == -1) + { + pBitDatBeg += widthBytes * (height -1); + } + + const unsigned char * pBitDat = pBitDatBeg; + int * countBuff = new int [width]; + if (countBuff == NULL) + { + qDebug() << "no enough memory"; + return -3; + } + memset(countBuff, 0, sizeof(int)*width); + + unsigned char tmpdat, mod; + int datsta = -1; + int count0 = 0; + int count1 = 0; + + int i, j, k, l; + for (i = 0; i < height; i++) // 行计数 + { + pTmpDat = pBitDat; + int countIdx = 0; + count0 = 0; + count1 = 0; + + for (j = 0, k = 0; (j < widthBytes) && (k < width); j++) // 行内扫描,检测出每段连续0和1的个数 + { + tmpdat = *pTmpDat++; + //qDebug()<> (8 - (width - k )); + } + + for (mod = 0x80; (mod != 0) && (k < width); k++, mod /= 2) + { + if ((tmpdat & mod) == 0) + { + if (datsta == 1) + { + count1 |= 0x80000000; + countBuff[countIdx] = count1; + countIdx++; + count1 = 0; + } + datsta = 0; + count0++; + } + else + { + if (datsta == 0) + { + countBuff[countIdx] = count0; + countIdx++; + count0 = 0; + } + datsta = 1; + count1++; + } + } + } + + if (count0 != 0) + { + countBuff[countIdx] = count0; + countIdx++; + count0 = 0; + } + + if (count1 != 0) + { + count1 |= 0x80000000; + countBuff[countIdx] = count1; + countIdx++; + count1 = 0; + } + + + int psta = 0; + int pcount = 0; + unsigned char tgtdat = 0, pmod = 0x20, nums; + + for (l = 0; l < countIdx; l++) // 分析数据,生成压缩数据 + { + if ((countBuff[l] & 0x80000000) != 0) + { + count1 = countBuff[l] & 0xfffffff; + + while (count1 != 0) + { + if (psta == 0) // 当前状态是原始数据 + { + if (pcount != 0) + { + while (count1 != 0 && pcount != 0) + { + tgtdat |= pmod; + pcount--; + count1--; + pmod *= 2; + } + + if (pcount == 0) // 够一个位图 + { + tgtdat &= 0x3f; + tmppr.append(tgtdat); // 添加 + tgtdat = 0x00; + } + } + } + if (pcount == 0 && count1 != 0) // + { + while (count1 != 0) + { + if (count1 <= 6) + { + psta = 0x00; // 位图模式 + tgtdat = psta; + pmod = 0x01; + pcount = 6; + break; + } + else + { + if (count1 > 64) + { + nums = 64; + } + else + { + nums = count1; + } + + psta = 0x40; + tgtdat = psta; + tgtdat |= (nums & 0x3f); + tmppr.append(tgtdat); // 添加 + //qDebug()<= 640) + { + nums = 64; + muti = 10; + psta = 0x80; + } + else if (count0 >= 64) + { + nums = (int)(count0/10); + muti = 10; + psta = 0x80; + } + else + { + nums = count0; + muti = 1; + psta = 0xC0; + } + + tgtdat = psta; + tgtdat |= (nums & 0x3f); + tmppr.append(tgtdat); // 添加 + //qDebug()<biHeight; + prHead.biWidth = pHead->biWidth; + + if (dir < 0) + { + prHead.compDir = 1; + } + else + { + prHead.compDir = 0; + } + + unsigned int prsize = tmppr.size(); + if (prsize >= pHead->biBitmapDatSize) // 压缩率不足 + { + prHead.compType = 0; // 不压缩 + prHead.datSize = pHead->biBitmapDatSize; + + tmppr.clear(); + pBitDat = pBitDatBeg; + + for (i = 0; i < height; i++) // 行计数 + { + tmppr.append((const char*)pBitDat, widthBytes); + pBitDat += widthBytes * dir; + } + } + else + { + prHead.compType = 1; + prHead.datSize = prsize; + } + + m_prDdat.append((char*)(&prHead), sizeof(CompBmpHead)); + m_prDdat.append(tmppr); + + return 0; +} + +int BWBmp::LoadPrBmp(QString filename) +{ + m_fileName = filename; + m_rbwDdat.clear(); + m_prDdat.clear(); + + QFile file(filename); + int rslt = file.open(QFile::ReadOnly); + if (rslt == 0) + { + qDebug() << "open file error" << filename; + return -1; + } + + m_prDdat = file.readAll(); + if (m_prDdat.size() <= 0) + { + file.close(); + qDebug() << "file size error, size=" << m_prDdat.size(); + m_prDdat.clear(); + return -2; + } + + file.close(); + return 0; +} + +int BWBmp::Unpress() +{ + m_rbwDdat.clear(); + QByteArray arrdat; + arrdat.clear(); + + QByteArray barr; + barr.clear(); + + int size = m_prDdat.size(); + if (size < (int)sizeof(CompBmpHead)) + { + qDebug() << "pr dat empty"; + return -1; + } + + CompBmpHead * pPrHead = (CompBmpHead *)(m_prDdat.data()); + const unsigned char * pPrDdat = (unsigned char *)(m_prDdat.data() + sizeof(CompBmpHead)); + size -= sizeof(CompBmpHead); + + + unsigned int biWidth = pPrHead->biWidth; + unsigned int biHeight = pPrHead->biHeight; + + int widthBytes = (int)((biWidth + 31) / 32) * 4; + + + BitmapHead bmpHead; + memset(&bmpHead, 0, sizeof(BitmapHead)); + + bmpHead.identifier = 0x4d42; // BM + bmpHead.bitDatOffset = 0x3E; + bmpHead.biSize = 0x28; + bmpHead.biPlanes = 1; + bmpHead.biBitPerPixel = 1; + bmpHead.biCompression = 0; + bmpHead.biHResolution = 3780; // 水平分辨率, 像素/米 + bmpHead.biVResolution = 3780; // 垂直分辨率, 像素/米 + bmpHead.biColors = 2; // 颜色数 + bmpHead.biImpColors = 2; // 重要颜色数 + bmpHead.palette[0].color = 0x00ffffff; + bmpHead.palette[1].color = 0x00000000; + + bmpHead.biWidth = biWidth; // 位图宽度,以像素为单位 + bmpHead.biHeight = biHeight; // 位图高度,以像素为单位 + bmpHead.biBitmapDatSize = widthBytes*biHeight; // 位图数据区的大小(字节数), 必须是4的整数倍 + bmpHead.fileSize = bmpHead.bitDatOffset + bmpHead.biBitmapDatSize; + +#define VAL_OUTBMP 0xff // 位图之外的默认数据 + + m_rbwDdat.append((char*)(&bmpHead), sizeof(BitmapHead)); + + unsigned char sdat = 0; + int count0,count1,flag; + count0 = count1 = 0; + flag = -1; + + for(int i = 0; i < size; i++) + { + count0 = count1 = 0; + flag = -1; + + sdat = pPrDdat[i]; + + if((sdat & 0xC0) == 0xC0) // 连续0 + { + count0 = sdat & 0x3f; + if (count0 == 0) + { + count0 = 64; + } + flag = 0; + } + else + { + if((sdat & 0x40) == 0x40) // 连续1 + { + count1 = sdat & 0x3f; + if (count1 == 0) + { + count1 = 64; + } + flag = 1; + } + else if((sdat & 0x80) == 0x80) // 连续10个0 + { + count0 = (sdat & 0x3f ) * 10; + if (count0 == 0) + { + count0 = 640; + } + flag = 0; + } + else // 原始数据 + { + //每行扫描时最后一个像素为原始数据时原始数据个数 + int pcount = 6; + int val = arrdat.size() % biWidth; + int cnt = biWidth - val; + int cnt1 = abs((int)biWidth - ((int)widthBytes-1) * 8); + if(cnt >= cnt1) + { + pcount = 6; + } + else + { + if(cnt > 6) + { + pcount = 6; + } + else + { + pcount = cnt; + } + } + + unsigned char sch = sdat & 0x3f; //够一个位图 + + unsigned char pmod = 0x01; + while (pcount != 0) + { + if((sch & pmod) != 0) // 为1 + { + arrdat.append((char)0x01); + } + else // 为0 + { + arrdat.append((char)0x00); + } + pcount--; + pmod *= 2; + } + + continue; + } + } + + int count = 0; + unsigned char ch = 0; + if(flag == 0) + { + count = count0; + ch = 0; + } + else if(flag == 1) + { + count = count1; + ch = 1; + } + + for(int j = 0; j < count; j++) + { + arrdat.append(ch); + } + } + + int num = 0; + unsigned int lst = ((biWidth/8)*8+8); + + for(unsigned int n = 0; n < biHeight; n++) + { + for(int j = 0; j < widthBytes; j++) + { + unsigned int cnt = j*8; + unsigned char abyte = 0; + + int idx = n*biWidth+j*8; + for(int i = 0; i < 8; i++, idx++, cnt++) + { + //qDebug()<<"idx"<= lst) + { + abyte = VAL_OUTBMP; // 默认值 + break; + } + else + { + abyte |= ((VAL_OUTBMP) >> (i)); // 默认值 + break; + } + } + + //if(abyte != 0) + { + //qDebug()< +#include + + +#ifndef u8 +#define u8 unsigned char +#endif + +#ifndef u16 +#define u16 unsigned short +#endif + +#ifndef u32 +#define u32 unsigned int +#endif + +#pragma pack(push, 1) //设定为1字节对齐 + +// 位图的调色板 +typedef union +{ + u32 color; + struct + { + u8 rgbBlue; + u8 rgbGreen; + u8 rgbRed; + u8 rgbReserved; + }__attribute__ ((packed)) rgb; +} BmpRgbQuad; + +// 位图文件头 +typedef struct +{ + u16 identifier; // 类型 一般为 "BM" + u32 fileSize; // 文件大小 + u32 reserved; // 保留 + u32 bitDatOffset; // 位图数据偏移,一般为 0x3E + + u32 biSize; // 位图信息头大小, 一般为 0x28 + u32 biWidth; // 位图宽度,以像素为单位 + u32 biHeight; // 位图高度,以像素为单位 + u16 biPlanes; // 位图的位面数,必须为1 + u16 biBitPerPixel; // 每个像素的位数, =1, 单色位图; =4, 16色; = 8, 256色; = 24 真彩色 + u32 biCompression; // 位图压缩类型, =0, 不压缩(BI_RGB); =1, BI_RLE8; = 2, BI_RLE4; = 3 BI_BITFIELDS; = 4, BI_JPEG; = 5, BI_PNG + u32 biBitmapDatSize;// 位图数据区的大小(字节数), 必须是4的整数倍 + u32 biHResolution; // 水平分辨率, 像素/米 + u32 biVResolution; // 垂直分辨率, 像素/米 + u32 biColors; // 颜色数 + u32 biImpColors; // 重要颜色数 + BmpRgbQuad palette[2]; // 调色板 +}__attribute__ ((packed)) BitmapHead; + +// 压缩位图文件头 +typedef struct +{ + // 0 + u32 fileId; // 整个位图文件标识 + u32 blkIdx; // 当前位图块号(位图分块后的编号) + u32 datSize; // 本块位图数据区的大小(字节数) + u32 biWidth; // 本块位图有效宽度,以像素为单位 + u32 biHeight; // 本块位图有效高度,以像素为单位 + u32 dataChecksum; // 本块位图数据累加校验和 + u32 begPos; // 本块位图起始位置(像素单位) + u32 endPos; // 本块位图结束位置(像素单位) + + // 32 + u8 compType; // 本块位图压缩类型, =0, 不压缩; =1, 按字节压缩; + u8 compDir; // 本块位图压缩方向, =0, 从上到下; =1, 从下到上;(喷墨方向) + + // 34 + u8 rev[64-2-34]; // 保留 + + // 62 + u16 checkCrc; // 前面字段的CRC校验 +}__attribute__ ((packed)) CompBmpHead; + +#pragma pack(pop) + + +class BWBmp +{ +public: + BWBmp(); + +public: + int LoadBiBmp(QString filename); + + int SavePrBmp(QString filename); + + int Compress(int idx = 0, int dir = 1); + + int LoadPrBmp(QString filename); + + int Unpress(); + + int SaveBiBmp(QString filename); + + QByteArray getPrBmpDat(); + +private: + + QByteArray m_bwDdat; + QByteArray m_prDdat; + + QByteArray m_rbwDdat; + + QString m_fileName; +}; + + + + + + +#endif // BWBMP_H diff --git a/bmp/creatprintbmp.cpp b/bmp/creatprintbmp.cpp new file mode 100644 index 0000000..988d2fd --- /dev/null +++ b/bmp/creatprintbmp.cpp @@ -0,0 +1,130 @@ +#include "creatprintbmp.h" + +CreatPrintBmp::CreatPrintBmp(QObject *parent) : QObject(parent) +{ + m_savePath.clear(); + m_mcIdx = 0; +} + +CreatPrintBmp::~CreatPrintBmp() +{ + +} + +void CreatPrintBmp::slotCreatBmp() +{ + + + + + + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(Qt::black)); + + //将picture保存为多个宽度为2400像素的bmp + int num = m_picture.width() / PIXMAPWIDTH; + int lwidth = m_picture.width() % PIXMAPWIDTH; + int height = m_picture.height(); + int offset = 0; + + if(lwidth != 0) + { + num += 1; + } + + QBitmap *pixmap = new QBitmap(PIXMAPWIDTH,height); + QPainter *pixPainter = new QPainter(); + pixPainter->setPen(pen); + pixPainter->begin(pixmap); + + for(int i = 0 ; i < num; i++) + { + pixmap->fill(Qt::white);//用白色填充 + pixPainter->drawPicture(offset,0,m_picture); + offset -= PIXMAPWIDTH; + + QString path = m_savePath+QString::number(i+1)+".bmp"; + bool bls = pixmap->save(path); + while(bls == false) + { + bls = pixmap->save(path); + qDebug()<<"pixmap save failed"; + } + + //压缩位图 + BWBmp bwBmp; + int rslt; + + rslt = bwBmp.LoadBiBmp(path); + if (rslt != 0) + { + qDebug() << "open file error" << path; + break; + } + rslt = bwBmp.Compress(); + if (rslt != 0) + { + qDebug() << "Compress error"; + break; + } + + rslt = bwBmp.SavePrBmp(path+".prbmp"); + if (rslt != 0) + { + qDebug() << "save prbmp error"; + break; + } + QByteArray dat = bwBmp.getPrBmpDat(); + siCreatOneBmpFinished(m_mcIdx,(u8*)dat.data(),dat.size()); + } + + pixPainter->end(); + + bool bla = pixPainter->isActive(); + while(bla == true) + { + bla = pixPainter->isActive(); + qDebug()<<"pixPainter isActive"; + } + + delete pixmap; + delete pixPainter; +} + +void CreatPrintBmp::setPicture(QPicture pic) +{ + m_picture = pic; +} + +void CreatPrintBmp::setPicture(QBitmap bitmap) +{ + //将图片画在picture上 + QPicture pic; + QPen pen; + pen.setWidth(1);//设置笔号 + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPixmap(0,0,bitmap); + painter.end(); + m_picture = pic; +} + +void CreatPrintBmp::setSavePath(QString path) +{ + m_savePath.clear(); + m_savePath = path; +} + +void CreatPrintBmp::setMcIdx(int idx) +{ + m_mcIdx = idx; +} + +QString CreatPrintBmp::getSavePath() +{ + return m_savePath; +} diff --git a/bmp/creatprintbmp.h b/bmp/creatprintbmp.h new file mode 100644 index 0000000..31b8569 --- /dev/null +++ b/bmp/creatprintbmp.h @@ -0,0 +1,41 @@ +#ifndef CREATPRINTBMP_H +#define CREATPRINTBMP_H + +#include +#include +#include +#include +#include +#include +#include +#include "bwbmp.h" +#include "main.h" + +class CreatPrintBmp : public QObject +{ + Q_OBJECT +public: + explicit CreatPrintBmp(QObject *parent = NULL); + ~CreatPrintBmp(); + +private: + QPicture m_picture;//绘图路径-线段 + QString m_savePath; + int m_mcIdx;//机器索引 + +public: + void setPicture(QPicture pic); + void setPicture(QBitmap bitmap); + void setSavePath(QString path); + void setMcIdx(int idx); + QString getSavePath(); + +signals: + void siCreatOneBmpFinished(int mcIdx,u8 *dat,int datSize); + +public slots: + void slotCreatBmp(); + +}; + +#endif // CREATPRINTBMP_H diff --git a/datafile/dxf.zip b/datafile/dxf.zip new file mode 100644 index 0000000000000000000000000000000000000000..f77cce181982e7da2753bbf3f7af6b7bc63c4d06 GIT binary patch literal 59343 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%0D8SJ&uRs#U{!}_)6NE0OrIE;%P6HqkXcm>uo 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 Z@xNbHe=6gDx_n~;s-FP>sOvvp{Xcojdwu`_ literal 0 HcmV?d00001 diff --git a/datafile/dxf/dxfhelper.cpp b/datafile/dxf/dxfhelper.cpp new file mode 100644 index 0000000..b2000fc --- /dev/null +++ b/datafile/dxf/dxfhelper.cpp @@ -0,0 +1,520 @@ +#include "dxfhelper.h" +#include "dxfreader.h" + +#include +#include + +DxfHelper::DxfHelper() +{ + +} + +double norm(double x, double y) +{ + return sqrt(x * x + y * y); +} + +QList DxfHelper::expandPolygon(QList polygon, float expand) +{ + QList new_polygon; + int len = polygon.length(); + if(len<3||qFuzzyIsNull(expand)) return polygon; + + bool repeatFlag = false; + if(polygon.first()==polygon.back()) { + repeatFlag = true; + polygon.removeLast(); + len = polygon.length(); + } + + int convertNum = 0; + for (int i = 0; i < len; i++) + { + QVector3D p = polygon[i]; + QVector3D p1 = polygon[i == 0 ? len - 1 : i - 1]; + QVector3D p2 = polygon[i == len - 1 ? 0 : i + 1]; + float v1x = p1.x() - p.x(); + float v1y = p1.y() - p.y(); + float n1 = norm(v1x, v1y); + float vv1x = v1x / n1; + float vv1y = v1y / n1; + float v2x = p2.x() - p.x(); + float v2y = p2.y() - p.y(); + float n2 = norm(v2x, v2y); + float vv2x = v2x / n2; + float vv2y = v2y / n2; + float vectorLen = -expand / sqrt((1 - (vv1x * vv2x + vv1y * vv2y)) / 2.0f); + float judge = v1x * v2y - v2x * v1y; + if (judge < 0) vectorLen *= -1; + if (judge < 0) convertNum++; + float vx = vv1x + vv2x; + float vy = vv1y + vv2y; + vectorLen = vectorLen / norm(vx, vy); + vx *= vectorLen; + vy *= vectorLen; + new_polygon.append(QVector3D(vx + p.x(), vy + p.y(), 0)); + } + if(convertNum==len) { + new_polygon.clear(); + for (int i = 0; i < len; i++) + { + QVector3D p = polygon[i]; + QVector3D p1 = polygon[i == 0 ? len - 1 : i - 1]; + QVector3D p2 = polygon[i == len - 1 ? 0 : i + 1]; + float v1x = p1.x() - p.x(); + float v1y = p1.y() - p.y(); + float n1 = norm(v1x, v1y); + float vv1x = v1x / n1; + float vv1y = v1y / n1; + float v2x = p2.x() - p.x(); + float v2y = p2.y() - p.y(); + float n2 = norm(v2x, v2y); + float vv2x = v2x / n2; + float vv2y = v2y / n2; + float vectorLen = -expand / sqrt((1 - (vv1x * vv2x + vv1y * vv2y)) / 2.0f); + float vx = vv1x + vv2x; + float vy = vv1y + vv2y; + vectorLen = vectorLen / norm(vx, vy); + vx *= vectorLen; + vy *= vectorLen; + new_polygon.append(QVector3D(vx + p.x(), vy + p.y(), 0)); + } + } + + if(repeatFlag) new_polygon.append(new_polygon.first()); + + return new_polygon; +} + +bool DxfHelper::generateDxf(const QString &fileName) +{ +// currentPos = QPointF(QRandomGenerator::global()->bounded(9999.99), QRandomGenerator::global()->bounded(9999.99)); + currentPos = QPointF(9999.99, 9999.99); + vertexIndex = 0; + controlIndex = 0; + dxfPaths.clear(); + + DxfReader dxfReader(fileName); + for(auto d: dxfReader.dxfText) { + //qDebug() << "text data:" << d.text.c_str() << d.angle << d.style.c_str() << d.height; + } + + for(auto d: dxfReader.dxfLinetypes) { + //qDebug() << "linetypes data:" << d.name.c_str() << d.flags << d.pattern << d.description.c_str() << d.patternLength << d.numberOfDashes; + } + + QVector linepath; + for(auto d: dxfReader.dxfLines) { + //qDebug() << "line data:" << d.x1 << d.y1 << d.z1 << "," << d.x2 << d.y2 << d.z2; + if(currentPos!=QPointF(d.x1, d.y1)) { + if(!linepath.isEmpty()) { + QList linelist; + foreach(auto point, linepath) linelist.append(QVector3D(point)); + linepath.clear(); + linelist = expandPolygon(linelist, expandOffset); + foreach(QVector3D point, linelist) { + double x = point.x(); + double y = point.y(); + linepath.append(QPointF(x, y)); + currentPos = QPointF(x, y); + } + dxfPaths.append(linepath); + linepath.clear(); + } + linepath.append(QPointF(d.x1, d.y1)); + linepath.append(QPointF(d.x2, d.y2)); + currentPos = QPointF(d.x2, d.y2); + } else { + linepath.append(QPointF(d.x2, d.y2)); + currentPos = QPointF(d.x2, d.y2); + } + } + if(!linepath.isEmpty()) { + QList linelist; + foreach(auto point, linepath) linelist.append(QVector3D(point)); + linepath.clear(); + linelist = expandPolygon(linelist, expandOffset); + foreach(QVector3D point, linelist) { + double x = point.x(); + double y = point.y(); + linepath.append(QPointF(x, y)); + currentPos = QPointF(x, y); + } + dxfPaths.append(linepath); + linepath.clear(); + } + + + for(auto d: dxfReader.dxfArcs) { + //qDebug() << "arcs data:" << d.cx << d.cy << d.cz << d.angle1 << d.angle2 << d.radius; + + + double cx = d.cx; + double cy = d.cy; +// double cz = d.cz; + double angle1 = d.angle1; + double angle2 = d.angle2; + double radius = d.radius; + + radius = radius + expandOffset; + + + QPainterPath path; + double startXPos = cx + cos(abs(angle1)*M_PI/180)*radius; + double startYPos = cy + sin(abs(angle1)*M_PI/180)*radius; + + path.moveTo(startXPos, startYPos); + + double angleStart ,anglePassed; + angleStart = angle1; + if(angleStart>=180) angleStart = angleStart-360; + anglePassed = angleStart-angle2; + if(angleStart<180) angleStart = -angleStart; + if(anglePassed<-360) anglePassed = anglePassed+360; + + QRectF rect(cx-radius, cy-radius, 2*radius, 2*radius); + path.arcTo(rect, angleStart, anglePassed); + + QVector arcpath; + for(double i = 0; i <= 1; i += 0.003) { // TODO: 步长随图片大小调整 + QPointF point = path.pointAtPercent(i); + double x = point.x(); + double y = point.y(); + arcpath.append(point); + currentPos=QPointF(x, y); + } + dxfPaths.append(arcpath); +// dxfPathList.append(path); + } + + for(auto d: dxfReader.dxfCircles) { + //qDebug() << "circle data:" << d.cx << d.cy << d.cz << d.radius; + + + double cx = d.cx; + double cy = d.cy; +// double cz = d.cz; + double radius = d.radius; + + radius = radius + expandOffset; + + + QPainterPath path; + path.moveTo(cx+radius, cy); + path.arcTo(cx-radius, cy-radius, 2*radius, 2*radius, 0, 360); + + QVector circlepath; + for(double i = 0; i <= 1; i += 0.003) { // TODO: 步长随图片大小调整 + QPointF point = path.pointAtPercent(i); + double x = point.x(); + double y = point.y(); + circlepath.append(point); + currentPos=QPointF(x, y); + } + dxfPaths.append(circlepath); +// dxfPathList.append(path); + } + + for(auto d: dxfReader.dxfEllipses) { // 起点角度要×ratio + //qDebug() << "ellipses data:" << d.cx << d.cy << d.cz << d.mx << d.my << d.mz << d.ratio << d.angle1 << d.angle2; + + double cx = d.cx; + double cy = d.cy; +// double cz = d.cz; + double mx = d.mx; + double my = d.my; +// double mz = d.mz; + double ratio = d.ratio; + double angle1 = d.angle1; + double angle2 = d.angle2; + + + double rab = sqrt((cx- mx)*(cx - mx) +(cy - my)*(cy - my)); + double resy = (expandOffset*(my-cy))/rab + my; + double resx = (expandOffset*(mx-cx))/rab + mx; + + mx = resx; + my = resy; + + + QPainterPath path; + double angle_1 = angle1; + double angle_2 = angle2; + while(angle_1>=3.14&&angle_2>=6.28) { + angle_1 -= M_PI; + angle_2 -= M_PI; + } + angle_1 = angle_1*180/M_PI; + angle_2 = angle_2*180/M_PI; + + double angleStart ,anglePassed; + angleStart = angle_1; + if(angleStart>=180) angleStart = angleStart-360; + anglePassed = angleStart-angle_2; + if(angleStart<180) angleStart = -angleStart; + if(anglePassed<-360) anglePassed = anglePassed+360; + + if(abs(anglePassed)<1) anglePassed = 360; + + double c_x = cx; + double c_y = cy; + double dl = sqrt(mx*mx+my*my); + double ds = dl*ratio; + + double rx; + double ry; + if(qFuzzyIsNull(mx)) { + rx = ds; ry = dl; + angleStart += 90; + } else { + rx = dl; ry = ds; + } + + double angle=angleStart; + if(angle<0) angle=-angle; + else if(angle>=0) angle = 360-angle; + //if(!qFuzzyCompare(abs(anglePassed),360)) angle *= ratio; + if(!qFuzzyCompare(float(anglePassed),(float)360)) angle *= ratio; + double a=qDegreesToRadians(angle); + double R=rx*ry/sqrt(pow(rx*sin(a),2)+pow(ry*cos(a),2)); //计算对应角度的半径 + double startXPos=c_x+R*cos(a); + double startYPos=c_y+R*sin(a); + path.moveTo(startXPos, startYPos); + + //qDebug() << c_x << c_y << rx << ry << angleStart << anglePassed << angle; + path.arcTo(c_x-rx, c_y-ry, 2*rx, 2*ry, angleStart, anglePassed); + + QVector ellipsepath; + for(double i = 0; i <= 1; i += 0.003) { // TODO: 步长随图片大小调整 + QPointF point = path.pointAtPercent(i); + double x = point.x(); + double y = point.y(); + ellipsepath.append(point); + currentPos=QPointF(x, y); + } + dxfPaths.append(ellipsepath); +// dxfPathList.append(path); + } + + for(auto d: dxfReader.dxfPolylines) { + //qDebug() << "polylines data:" << d.m << d.n << d.flags << d.number << d.elevation; + + QList pointlist; + QVector path; + for(unsigned int i = 0; i < d.number; i++) { + double x = dxfReader.dxfVertexs.at(vertexIndex).x; + double y = dxfReader.dxfVertexs.at(vertexIndex).y; + double z = dxfReader.dxfVertexs.at(vertexIndex).z; + pointlist.append(QVector3D(x, y, z)); + vertexIndex++; + } + + pointlist = expandPolygon(pointlist, expandOffset); + foreach(QVector3D point, pointlist) { + double x = point.x(); + double y = point.y(); + path.append(QPointF(x, y)); + currentPos = QPointF(x, y); + } + + if(d.flags) { + double x = pointlist.first().x(); + double y = pointlist.first().y(); + path.append(QPointF(x, y)); + currentPos = QPointF(x, y); + } + dxfPaths.append(path); + } + +// for(auto d: dxfReader.dxfVertexs) { +// qDebug() << "vertexs data:" << d.x << d.y << d.z << d.bulge; +// } + + for(auto d: dxfReader.dxfPoints) { + //qDebug() << "points data:" << d.x << d.y << d.z; + QVector path; + path.append(QPointF(d.x, d.y)); + dxfPaths.append(path); + currentPos = QPointF(d.x, d.y); + } + + for(auto d: dxfReader.dxfSplines) { + //qDebug() << "splines data:" << d.nFit << d.flags << d.degree << d.nKnots << d.nControl << d.tangentEndX << d.tangentEndY << d.tangentEndZ << d.tangentStartX << d.tangentStartY << d.tangentStartZ; + std::vector pointList; + for(unsigned int i = 0; i < d.nControl; i++) { + int x = dxfReader.dxfControlPoints.at(controlIndex).x; + int y = dxfReader.dxfControlPoints.at(controlIndex).y; + pointList.push_back(QVector2D(x, y)); + currentPos = QPointF(x, y); + controlIndex++; + } + + QList templist; + foreach(auto point, pointList) templist.append(point); + templist = expandPolygon(templist, expandOffset); + + QVector inputList; + foreach(auto point, templist) inputList.append(point.toVector2D()); + inputList.push_front(inputList.first()); + inputList.push_back(inputList.back()); +// std::vector finalList(inputList.begin(), inputList.end()); + +// SplineHelper splineHelper(finalList, TypeCubicBSpline); +// auto splinePath = splineHelper.getSplinePath(); + +// dxfPaths.append(splinePath); + } + +// for(auto d: dxfReader.dxfControlPoints) { +// qDebug() << "control points data:" << d.w << d.x << d.y << d.z; +// } + +// for(auto d: dxfReader.dxfXLines) { +// qDebug() << "XLines data:" << d.bx << d.by << d.bz << d.dx << d.dy << d.dz; +// } + +// for(auto d: dxfReader.dxfRays) { +// qDebug() << "rays data:" << d.bx << d.by << d.bz << d.dx << d.dy << d.dz; +// } + +// for(auto d: dxfReader.dxfFitPoints) { +// qDebug() << "fit points data:" << d.x << d.y << d.z; +// } + +// for(auto d: dxfReader.dxfHatchs) { +// qDebug() << "hatchs data:" << d.angle << d.scale << d.solid << d.originX << d.originY << d.pattern.c_str() << d.numLoops; +// } + +// for(auto d: dxfReader.dxfHatchLoops) { +// qDebug() << "hatchLoops data:" << d.numEdges; +// } + +// for(auto d: dxfReader.dxfHatchEdges) { +// qDebug() << "hatchEdges data:" << d.cx << d.cy << d.mx << d.my << d.x1 << d.y1 << d.x2 << d.y2 << d.ccw << d.nFit << d.ratio << d.angle1 << d.angle2 << d.degree << d.nKnots << d.radius << d.defined << d.weights << d.nControl << d.periodic << d.rational << d.vertices << d.fitPoints << d.endTangentX << d.endTangentY << d.endTangentY << d.controlPoints << d.startTangentX << d.startTangentY; +// } + + return true; +} + +void DxfHelper::matchDXFSize() +{ + double minx = __DBL_MAX__; + double maxx = __DBL_MIN__; + double miny = __DBL_MAX__; + double maxy = __DBL_MIN__; + foreach (QVector path, dxfPaths) { + for(int i = 0; i < path.length(); i++) { + QPointF point = path.at(i); + double x = point.x(); + double y = point.y(); + if(xmaxx) maxx = x; + if(ymaxy) maxy = y; + } + } + int width = maxx - minx; + int height = maxy - miny; + imageSize = QSize(width, height); + dxfBorderList.clear(); + dxfBorderList.append(minx); + dxfBorderList.append(miny); + dxfBorderList.append(maxx); + dxfBorderList.append(maxy); +} + +QImage DxfHelper::generateDXFImage() +{ + matchDXFSize(); + double minx = dxfBorderList.at(0); + double miny = dxfBorderList.at(1); + int penwidth = imageSize.width()/400; + int border = penwidth; + QImage image((imageSize.width()+2*border), (imageSize.height()+2*border), QImage::Format_ARGB32); + image.fill(Qt::white); + QPainter p(&image); + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 抗锯齿和使用平滑转换算法 + QPen pen; + if(penwidth<1) penwidth = 1; + pen.setWidth(penwidth); + pen.setColor(Qt::black); + p.setPen(pen); + QPainterPath painterpath; + foreach (QVector path, dxfPaths) { + for(int i = 0; i < path.length(); i++) { + double x = path.at(i).x()-minx; + double y = path.at(i).y()-miny; + y = imageSize.height()-y; + x += border; + y += border; + QPointF point(x, y); + if(i == 0) painterpath.moveTo(point); + else painterpath.lineTo(point); + } +// dxfPathList.append(painterpath); + } + //qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]\t"<< "dxf path length:" < DxfHelper::getDxfBorderList() const +{ + return dxfBorderList; +} + +QSize DxfHelper::getImageSize() const +{ + return imageSize; +} + +QList DxfHelper::getDxfPathList() const +{ + return dxfPathList; +} + +QVector > DxfHelper::getDxfPaths() const +{ + return dxfPaths; +} + +QList DxfHelper::getDxfLineList() const +{ + return dxfLineList; +} + +QList DxfHelper::getDxfRectList() const +{ + return dxfRectList; +} + +QList DxfHelper::getDxfArcList() const +{ + return dxfArcList; +} + +QList DxfHelper::getDxfCircleList() const +{ + return dxfCircleList; +} + +QList DxfHelper::getDxfEllipseList() const +{ + return dxfEllipseList; +} + +QList DxfHelper::getDxfPolylineList() const +{ + return dxfPolylineList; +} + +QList DxfHelper::getDxfSplineList() const +{ + return dxfSplineList; +} + +void DxfHelper::setExpandOffset(double value) +{ + expandOffset = value; +} diff --git a/datafile/dxf/dxfhelper.h b/datafile/dxf/dxfhelper.h new file mode 100644 index 0000000..a255d52 --- /dev/null +++ b/datafile/dxf/dxfhelper.h @@ -0,0 +1,114 @@ +#ifndef DXFHELPER_H +#define DXFHELPER_H + +#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +//qRegisterMetaType >("QVector"); +//qRegisterMetaType("QList"); + +struct DXFLine { + double x1; + double y1; + double z1; + double x2; + double y2; + double z2; +}; + +struct DXFRect { + QList list; +}; + + +struct DXFArc { + double cx; + double cy; + double cz; + double angle1; + double angle2; + double radius; +}; + +struct DXFCircle { + double cx; + double cy; + double cz; + double radius; +}; + +struct DXFEllipse { + double cx; + double cy; + double cz; + double mx; + double my; + double mz; + double angle1; + double angle2; + double ratio; +}; + +struct DXFPolyline { + double flags; + double number; + QList list; +}; + +struct DXFSpline { + double nControl; + QList controlPoints; +}; + + +class DxfHelper +{ +public: + DxfHelper(); + QList expandPolygon(QList polygon, float expand); + bool generateDxf(const QString &fileName); + QVector> getDxfPaths() const; + + QList getDxfLineList() const; + QList getDxfRectList() const; + QList getDxfArcList() const; + QList getDxfCircleList() const; + QList getDxfEllipseList() const; + QList getDxfPolylineList() const; + QList getDxfSplineList() const; + + void setExpandOffset(double value); + + void matchDXFSize(); + QImage generateDXFImage(); + QList getDxfPathList() const; + QSize getImageSize() const; + QList getDxfBorderList() const; +private: + QPointF currentPos; + unsigned int vertexIndex = 0; + unsigned int controlIndex = 0; + QVector> dxfPaths; + QList dxfPathList; + + double expandOffset = 0; + + QList dxfLineList; + QList dxfRectList; + QList dxfArcList; + QList dxfCircleList; + QList dxfEllipseList; + QList dxfPolylineList; + QList dxfSplineList; + QList dxfBorderList; + QSize imageSize; +}; + +#endif // DXFHELPER_H diff --git a/datafile/dxf/dxflib/dl_attributes.h b/datafile/dxf/dxflib/dl_attributes.h new file mode 100644 index 0000000..00f9ddc --- /dev/null +++ b/datafile/dxf/dxflib/dl_attributes.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_ATTRIBUTES_H +#define DL_ATTRIBUTES_H + +#include "dl_global.h" + +#include +#include + +#include "dl_codes.h" + +/** + * Storing and passing around attributes. Attributes + * are the layer name, color, width and line type. + * + * @author Andrew Mustun + */ +class DXFLIB_EXPORT DL_Attributes { + +public: + + /** + * Default constructor. + */ + DL_Attributes() : + layer(""), + color(0), + color24(-1), + width(0), + linetype("BYLAYER"), + linetypeScale(1.0), + handle(-1), + inPaperSpace(false) { + } + + /** + * Constructor for DXF attributes. + * + * @param layer Layer name for this entity or NULL for no layer + * (every entity should be on a named layer!). + * @param color Color number (0..256). 0 = BYBLOCK, 256 = BYLAYER. + * @param width Line thickness. Defaults to zero. -1 = BYLAYER, + * -2 = BYBLOCK, -3 = default width + * @param linetype Line type name or "BYLAYER" or "BYBLOCK". Defaults + * to "BYLAYER" + */ + DL_Attributes(const std::string& layer, + int color, int width, + const std::string& linetype, + double linetypeScale) : + layer(layer), + color(color), + color24(-1), + width(width), + linetype(linetype), + linetypeScale(linetypeScale), + handle(-1), + inPaperSpace(false) { + + } + + /** + * Constructor for DXF attributes. + * + * @param layer Layer name for this entity or NULL for no layer + * (every entity should be on a named layer!). + * @param color Color number (0..256). 0 = BYBLOCK, 256 = BYLAYER. + * @param color24 24 bit color (0x00RRGGBB, see DXF reference). + * @param width Line thickness. Defaults to zero. -1 = BYLAYER, + * -2 = BYBLOCK, -3 = default width + * @param linetype Line type name or "BYLAYER" or "BYBLOCK". Defaults + * to "BYLAYER" + */ + DL_Attributes(const std::string& layer, + int color, int color24, int width, + const std::string& linetype, + int handle=-1) : + layer(layer), + color(color), + color24(color24), + width(width), + linetype(linetype), + linetypeScale(1.0), + handle(handle), + inPaperSpace(false) { + } + + /** + * Sets the layer. If the given pointer points to NULL, the + * new layer name will be an empty but valid string. + */ + void setLayer(const std::string& layer) { + this->layer = layer; + } + + /** + * @return Layer name. + */ + std::string getLayer() const { + return layer; + } + + /** + * Sets the color. + * + * @see DL_Codes, dxfColors + */ + void setColor(int color) { + this->color = color; + } + + /** + * Sets the 24bit color. + * + * @see DL_Codes, dxfColors + */ + void setColor24(int color) { + this->color24 = color; + } + + /** + * @return Color. + * + * @see DL_Codes, dxfColors + */ + int getColor() const { + return color; + } + + /** + * @return 24 bit color or -1 if no 24bit color is defined. + * + * @see DL_Codes, dxfColors + */ + int getColor24() const { + return color24; + } + + /** + * Sets the width. + */ + void setWidth(int width) { + this->width = width; + } + + /** + * @return Width. + */ + int getWidth() const { + return width; + } + + /** + * Sets the line type. This can be any string and is not + * checked to be a valid line type. + */ + void setLinetype(const std::string& linetype) { + this->linetype = linetype; + } + + /** + * Sets the entity specific line type scale. + */ + void setLinetypeScale(double linetypeScale) { + this->linetypeScale = linetypeScale; + } + + double getLinetypeScale() const { + return linetypeScale; + } + + /** + * @return Line type. + */ + std::string getLinetype() const { + if (linetype.length()==0) { + return "BYLAYER"; + } else { + return linetype; + } + } + + void setHandle(int h) { + handle = h; + } + + int getHandle() const { + return handle; + } + + void setInPaperSpace(bool on) { + inPaperSpace = on; + } + + bool isInPaperSpace() const { + return inPaperSpace; + } + +private: + std::string layer; + int color; + int color24; + int width; + std::string linetype; + double linetypeScale; + int handle; + + // DXF code 67 (true: entity in paper space, false: entity in model space (default): + bool inPaperSpace; +}; + +#endif + +// EOF diff --git a/datafile/dxf/dxflib/dl_codes.h b/datafile/dxf/dxflib/dl_codes.h new file mode 100644 index 0000000..99ae5b6 --- /dev/null +++ b/datafile/dxf/dxflib/dl_codes.h @@ -0,0 +1,546 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** Copyright (C) 2001 Robert J. Campbell Jr. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/** + * Defines common DXF codes and constants. + */ + +#ifndef DXF_CODES_H +#define DXF_CODES_H + +#include "dl_global.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//#if defined(__OS2__)||defined(__EMX__) +//#define strcasecmp(s,t) stricmp(s,t) +//#endif + +//#if defined(_WIN32) +//#define strcasecmp(s,t) _stricmp(s,t) +//#endif + + +#ifdef _WIN32 +#undef M_PI +#define M_PI 3.14159265358979323846 +//#pragma warning(disable : 4800) +#endif + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#define DL_DXF_MAXLINE 1024 +#define DL_DXF_MAXGROUPCODE 1100 + +// used to mark invalid vectors: +//#define DL_DXF_MAXDOUBLE 1.0E+10 + +/** + * Codes for colors and DXF versions. + */ +class DXFLIB_EXPORT DL_Codes { +public: + /** + * Standard DXF colors. + */ + enum color { + black = 250, + green = 3, + red = 1, + brown = 15, + yellow = 2, + cyan = 4, + magenta = 6, + gray = 8, + blue = 5, + l_blue = 163, + l_green = 121, + l_cyan = 131, + l_red = 23, + l_magenta = 221, + l_gray = 252, + white = 7, + bylayer = 256, + byblock = 0 + }; + + /** + * Version numbers for the DXF Format. + */ + enum version { + AC1009_MIN, // R12, minimalistic + AC1009, // R12 + AC1012, + AC1014, + AC1015 // R2000 + }; +}; + + +// Extended color palette: +// The first entry is only for direct indexing starting with [1] +// Color 1 is red (1,0,0) +const double dxfColors[][3] = { + {0,0,0}, // unused + {1,0,0}, // 1 + {1,1,0}, + {0,1,0}, + {0,1,1}, + {0,0,1}, + {1,0,1}, + {1,1,1}, // black or white + {0.5,0.5,0.5}, + {0.75,0.75,0.75}, + {1,0,0}, // 10 + {1,0.5,0.5}, + {0.65,0,0}, + {0.65,0.325,0.325}, + {0.5,0,0}, + {0.5,0.25,0.25}, + {0.3,0,0}, + {0.3,0.15,0.15}, + {0.15,0,0}, + {0.15,0.075,0.075}, + {1,0.25,0}, // 20 + {1,0.625,0.5}, + {0.65,0.1625,0}, + {0.65,0.4063,0.325}, + {0.5,0.125,0}, + {0.5,0.3125,0.25}, + {0.3,0.075,0}, + {0.3,0.1875,0.15}, + {0.15,0.0375,0}, + {0.15,0.0938,0.075}, + {1,0.5,0}, // 30 + {1,0.75,0.5}, + {0.65,0.325,0}, + {0.65,0.4875,0.325}, + {0.5,0.25,0}, + {0.5,0.375,0.25}, + {0.3,0.15,0}, + {0.3,0.225,0.15}, + {0.15,0.075,0}, + {0.15,0.1125,0.075}, + {1,0.75,0}, // 40 + {1,0.875,0.5}, + {0.65,0.4875,0}, + {0.65,0.5688,0.325}, + {0.5,0.375,0}, + {0.5,0.4375,0.25}, + {0.3,0.225,0}, + {0.3,0.2625,0.15}, + {0.15,0.1125,0}, + {0.15,0.1313,0.075}, + {1,1,0}, // 50 + {1,1,0.5}, + {0.65,0.65,0}, + {0.65,0.65,0.325}, + {0.5,0.5,0}, + {0.5,0.5,0.25}, + {0.3,0.3,0}, + {0.3,0.3,0.15}, + {0.15,0.15,0}, + {0.15,0.15,0.075}, + {0.75,1,0}, // 60 + {0.875,1,0.5}, + {0.4875,0.65,0}, + {0.5688,0.65,0.325}, + {0.375,0.5,0}, + {0.4375,0.5,0.25}, + {0.225,0.3,0}, + {0.2625,0.3,0.15}, + {0.1125,0.15,0}, + {0.1313,0.15,0.075}, + {0.5,1,0}, // 70 + {0.75,1,0.5}, + {0.325,0.65,0}, + {0.4875,0.65,0.325}, + {0.25,0.5,0}, + {0.375,0.5,0.25}, + {0.15,0.3,0}, + {0.225,0.3,0.15}, + {0.075,0.15,0}, + {0.1125,0.15,0.075}, + {0.25,1,0}, // 80 + {0.625,1,0.5}, + {0.1625,0.65,0}, + {0.4063,0.65,0.325}, + {0.125,0.5,0}, + {0.3125,0.5,0.25}, + {0.075,0.3,0}, + {0.1875,0.3,0.15}, + {0.0375,0.15,0}, + {0.0938,0.15,0.075}, + {0,1,0}, // 90 + {0.5,1,0.5}, + {0,0.65,0}, + {0.325,0.65,0.325}, + {0,0.5,0}, + {0.25,0.5,0.25}, + {0,0.3,0}, + {0.15,0.3,0.15}, + {0,0.15,0}, + {0.075,0.15,0.075}, + {0,1,0.25}, // 100 + {0.5,1,0.625}, + {0,0.65,0.1625}, + {0.325,0.65,0.4063}, + {0,0.5,0.125}, + {0.25,0.5,0.3125}, + {0,0.3,0.075}, + {0.15,0.3,0.1875}, + {0,0.15,0.0375}, + {0.075,0.15,0.0938}, + {0,1,0.5}, // 110 + {0.5,1,0.75}, + {0,0.65,0.325}, + {0.325,0.65,0.4875}, + {0,0.5,0.25}, + {0.25,0.5,0.375}, + {0,0.3,0.15}, + {0.15,0.3,0.225}, + {0,0.15,0.075}, + {0.075,0.15,0.1125}, + {0,1,0.75}, // 120 + {0.5,1,0.875}, + {0,0.65,0.4875}, + {0.325,0.65,0.5688}, + {0,0.5,0.375}, + {0.25,0.5,0.4375}, + {0,0.3,0.225}, + {0.15,0.3,0.2625}, + {0,0.15,0.1125}, + {0.075,0.15,0.1313}, + {0,1,1}, // 130 + {0.5,1,1}, + {0,0.65,0.65}, + {0.325,0.65,0.65}, + {0,0.5,0.5}, + {0.25,0.5,0.5}, + {0,0.3,0.3}, + {0.15,0.3,0.3}, + {0,0.15,0.15}, + {0.075,0.15,0.15}, + {0,0.75,1}, // 140 + {0.5,0.875,1}, + {0,0.4875,0.65}, + {0.325,0.5688,0.65}, + {0,0.375,0.5}, + {0.25,0.4375,0.5}, + {0,0.225,0.3}, + {0.15,0.2625,0.3}, + {0,0.1125,0.15}, + {0.075,0.1313,0.15}, + {0,0.5,1}, // 150 + {0.5,0.75,1}, + {0,0.325,0.65}, + {0.325,0.4875,0.65}, + {0,0.25,0.5}, + {0.25,0.375,0.5}, + {0,0.15,0.3}, + {0.15,0.225,0.3}, + {0,0.075,0.15}, + {0.075,0.1125,0.15}, + {0,0.25,1}, // 160 + {0.5,0.625,1}, + {0,0.1625,0.65}, + {0.325,0.4063,0.65}, + {0,0.125,0.5}, + {0.25,0.3125,0.5}, + {0,0.075,0.3}, + {0.15,0.1875,0.3}, + {0,0.0375,0.15}, + {0.075,0.0938,0.15}, + {0,0,1}, // 170 + {0.5,0.5,1}, + {0,0,0.65}, + {0.325,0.325,0.65}, + {0,0,0.5}, + {0.25,0.25,0.5}, + {0,0,0.3}, + {0.15,0.15,0.3}, + {0,0,0.15}, + {0.075,0.075,0.15}, + {0.25,0,1}, // 180 + {0.625,0.5,1}, + {0.1625,0,0.65}, + {0.4063,0.325,0.65}, + {0.125,0,0.5}, + {0.3125,0.25,0.5}, + {0.075,0,0.3}, + {0.1875,0.15,0.3}, + {0.0375,0,0.15}, + {0.0938,0.075,0.15}, + {0.5,0,1}, // 190 + {0.75,0.5,1}, + {0.325,0,0.65}, + {0.4875,0.325,0.65}, + {0.25,0,0.5}, + {0.375,0.25,0.5}, + {0.15,0,0.3}, + {0.225,0.15,0.3}, + {0.075,0,0.15}, + {0.1125,0.075,0.15}, + {0.75,0,1}, // 200 + {0.875,0.5,1}, + {0.4875,0,0.65}, + {0.5688,0.325,0.65}, + {0.375,0,0.5}, + {0.4375,0.25,0.5}, + {0.225,0,0.3}, + {0.2625,0.15,0.3}, + {0.1125,0,0.15}, + {0.1313,0.075,0.15}, + {1,0,1}, // 210 + {1,0.5,1}, + {0.65,0,0.65}, + {0.65,0.325,0.65}, + {0.5,0,0.5}, + {0.5,0.25,0.5}, + {0.3,0,0.3}, + {0.3,0.15,0.3}, + {0.15,0,0.15}, + {0.15,0.075,0.15}, + {1,0,0.75}, // 220 + {1,0.5,0.875}, + {0.65,0,0.4875}, + {0.65,0.325,0.5688}, + {0.5,0,0.375}, + {0.5,0.25,0.4375}, + {0.3,0,0.225}, + {0.3,0.15,0.2625}, + {0.15,0,0.1125}, + {0.15,0.075,0.1313}, + {1,0,0.5}, // 230 + {1,0.5,0.75}, + {0.65,0,0.325}, + {0.65,0.325,0.4875}, + {0.5,0,0.25}, + {0.5,0.25,0.375}, + {0.3,0,0.15}, + {0.3,0.15,0.225}, + {0.15,0,0.075}, + {0.15,0.075,0.1125}, + {1,0,0.25}, // 240 + {1,0.5,0.625}, + {0.65,0,0.1625}, + {0.65,0.325,0.4063}, + {0.5,0,0.125}, + {0.5,0.25,0.3125}, + {0.3,0,0.075}, + {0.3,0.15,0.1875}, + {0.15,0,0.0375}, + {0.15,0.075,0.0938}, + {0.33,0.33,0.33}, // 250 + {0.464,0.464,0.464}, + {0.598,0.598,0.598}, + {0.732,0.732,0.732}, + {0.866,0.866,0.866}, + {1,1,1} // 255 + } + ; + + +// AutoCAD VERSION aliases +#define DL_VERSION_R12 DL_Codes::AC1009 +#define DL_VERSION_LT2 DL_Codes::AC1009 +#define DL_VERSION_R13 DL_Codes::AC1012 // not supported yet +#define DL_VERSION_LT95 DL_Codes::AC1012 // not supported yet +#define DL_VERSION_R14 DL_Codes::AC1014 // not supported yet +#define DL_VERSION_LT97 DL_Codes::AC1014 // not supported yet +#define DL_VERSION_LT98 DL_Codes::AC1014 // not supported yet +#define DL_VERSION_2000 DL_Codes::AC1015 +#define DL_VERSION_2002 DL_Codes::AC1015 + + +// DXF Group Codes: + +// Strings +#define DL_STRGRP_START 0 +#define DL_STRGRP_END 9 + +// Coordinates +#define DL_CRDGRP_START 10 +#define DL_CRDGRP_END 19 + +// Real values +#define DL_RLGRP_START 38 +#define DL_RLGRP_END 59 + +// Short integer values +#define DL_SHOGRP_START 60 +#define DL_SHOGRP_END 79 + +// New in Release 13, +#define DL_SUBCLASS 100 + +// More coordinates +#define DL_CRD2GRP_START 210 +#define DL_CRD2GRP_END 239 + +// Extended data strings +#define DL_ESTRGRP_START 1000 +#define DL_ESTRGRP_END 1009 + +// Extended data reals +#define DL_ERLGRP_START 1010 +#define DL_ERLGRP_END 1059 + + +#define DL_Y8_COORD_CODE 28 +#define DL_Z0_COORD_CODE 30 +#define DL_Z8_COORD_CODE 38 + +#define DL_POINT_COORD_CODE 10 +#define DL_INSERT_COORD_CODE 10 + +#define DL_CRD2GRP_START 210 +#define DL_CRD2GRP_END 239 + +#define DL_THICKNESS 39 +#define DL_FIRST_REAL_CODE THICKNESS +#define DL_LAST_REAL_CODE 59 +#define DL_FIRST_INT_CODE 60 +#define DL_ATTFLAGS_CODE 70 +#define DL_PLINE_FLAGS_CODE 70 +#define DL_LAYER_FLAGS_CODE 70 +#define DL_FLD_LEN_CODE 73 // Inside ATTRIB resbuf +#define DL_LAST_INT_CODE 79 +#define DL_X_EXTRU_CODE 210 +#define DL_Y_EXTRU_CODE 220 +#define DL_Z_EXTRU_CODE 230 +#define DL_COMMENT_CODE 999 + +// Start and endpoints of a line +#define DL_LINE_START_CODE 10 // Followed by x coord +#define DL_LINE_END_CODE 11 // Followed by x coord + +// Some codes used by blocks +#define DL_BLOCK_FLAGS_CODE 70 // An int containing flags +#define DL_BLOCK_BASE_CODE 10 // Origin of block definition +#define DL_XREF_DEPENDENT 16 // If a block contains an XREF +#define DL_XREF_RESOLVED 32 // If a XREF resolved ok +#define DL_REFERENCED 64 // If a block is ref'd in DWG + +#define DL_XSCALE_CODE 41 +#define DL_YSCALE_CODE 42 +#define DL_ANGLE_CODE 50 +#define DL_INS_POINT_CODE 10 // Followed by x of ins pnt +#define DL_NAME2_CODE 3 // Second appearance of name + +// Some codes used by circle entities +#define DL_CENTER_CODE 10 // Followed by x of center +#define DL_RADIUS_CODE 40 // Followd by radius of circle + +#define DL_COND_OP_CODE -4 // Conditional op,ads_ssget + +// When using ads_buildlist you MUST use RTDXF0 instead of these +#define DL_ENTITY_TYPE_CODE 0 // Then there is LINE, 3DFACE.. +#define DL_SES_CODE 0 // Start End String Code +#define DL_FILE_SEP_CODE 0 // File separator +#define DL_SOT_CODE 0 // Start Of Table +#define DL_TEXTVAL_CODE 1 +#define DL_NAME_CODE 2 +#define DL_BLOCK_NAME_CODE 2 +#define DL_SECTION_NAME_CODE 2 +#define DL_ENT_HAND_CODE 5 // What follows is hexa string +#define DL_TXT_STYLE_CODE 7 // Inside attributes +#define DL_LAYER_NAME_CODE 8 // What follows is layer name +#define DL_FIRST_XCOORD_CODE 10 // Group code x of 1st coord +#define DL_FIRST_YCOORD_CODE 20 // Group code y of 1st coord +#define DL_FIRST_ZCOORD_CODE 30 // Group code z of 1st coord +#define DL_L_START_CODE 10 +#define DL_L_END_CODE 11 +#define DL_TXTHI_CODE 40 +#define DL_SCALE_X_CODE 41 +#define DL_SCALE_Y_CODE 42 +#define DL_SCALE_Z_CODE 43 +#define DL_BULGE_CODE 42 // Used in PLINE verts for arcs +#define DL_ROTATION_CODE 50 +#define DL_COLOUR_CODE 62 // What follows is a color int +#define DL_LTYPE_CODE 6 // What follows is a linetype + + +// Attribute flags +#define DL_ATTS_FOLLOW_CODE 66 +#define DL_ATT_TAG_CODE 2 +#define DL_ATT_VAL_CODE 1 +#define DL_ATT_FLAGS_CODE 70 // 4 1 bit flags as follows... +#define DL_ATT_INVIS_FLAG 1 +#define DL_ATT_CONST_FLAG 2 +#define DL_ATT_VERIFY_FLAG 4 // Prompt and verify +#define DL_ATT_PRESET_FLAG 8 // No prompt and no verify + +// PLINE defines +// Flags +#define DL_OPEN_PLINE 0x00 +#define DL_CLOSED_PLINE 0x01 +#define DL_POLYLINE3D 0x80 +#define DL_PFACE_MESH 0x40 +#define DL_PGON_MESH 0x10 +// Vertices follow entity, required in POLYLINES +#define DL_VERTS_FOLLOW_CODE 66 // Value should always be 1 +#define DL_VERTEX_COORD_CODE 10 + + +// LAYER flags +#define DL_FROZEN 1 +#define DL_FROZEN_BY_DEF 2 +#define DL_LOCKED 4 +#define DL_OBJECT_USED 64 // Object is ref'd in the dwg + +#define DL_BLOCK_EN_CODE -2 // Block entity definition +#define DL_E_NAME -1 // Entity name + +// Extended data codes +#define DL_EXTD_SENTINEL (-3) +#define DL_EXTD_STR 1000 +#define DL_EXTD_APP_NAME 1001 +#define DL_EXTD_CTL_STR 1002 +#define DL_EXTD_LYR_STR 1003 +#define DL_EXTD_CHUNK 1004 +#define DL_EXTD_HANDLE 1005 +#define DL_EXTD_POINT 1010 +#define DL_EXTD_POS 1011 +#define DL_EXTD_DISP 1012 +#define DL_EXTD_DIR 1013 +#define DL_EXTD_FLOAT 1040 +#define DL_EXTD_DIST 1041 +#define DL_EXTD_SCALE 1042 +#define DL_EXTD_INT16 1070 +#define DL_EXTD_INT32 1071 + +// UCS codes for use in ads_trans +#define DL_WCS_TRANS_CODE 0 +#define DL_UCS_TRANS_CODE 1 +#define DL_DCS_TRANS_CODE 2 +#define DL_PCS_TRANS_CODE 3 + +#endif + diff --git a/datafile/dxf/dxflib/dl_creationadapter.h b/datafile/dxf/dxflib/dl_creationadapter.h new file mode 100644 index 0000000..0d12ead --- /dev/null +++ b/datafile/dxf/dxflib/dl_creationadapter.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_CREATIONADAPTER_H +#define DL_CREATIONADAPTER_H + +#include "dl_global.h" + +#include "dl_creationinterface.h" + +/** + * An abstract adapter class for receiving DXF events when a DXF file is being read. + * The methods in this class are empty. This class exists as convenience for creating + * listener objects. + * + * @author Andrew Mustun + */ +class DXFLIB_EXPORT DL_CreationAdapter : public DL_CreationInterface { +public: + DL_CreationAdapter() {} + virtual ~DL_CreationAdapter() {} + virtual void processCodeValuePair(unsigned int, const std::string&) {} + virtual void endSection() {} + virtual void addLayer(const DL_LayerData&) {} + virtual void addLinetype(const DL_LinetypeData&) {} + virtual void addLinetypeDash(double) {} + virtual void addBlock(const DL_BlockData&) {} + virtual void endBlock() {} + virtual void addTextStyle(const DL_StyleData&) {} + virtual void addPoint(const DL_PointData&) {} + virtual void addLine(const DL_LineData&) {} + virtual void addXLine(const DL_XLineData&) {} + virtual void addRay(const DL_RayData&) {} + + virtual void addArc(const DL_ArcData&) {} + virtual void addCircle(const DL_CircleData&) {} + virtual void addEllipse(const DL_EllipseData&) {} + + virtual void addPolyline(const DL_PolylineData&) {} + virtual void addVertex(const DL_VertexData&) {} + + virtual void addSpline(const DL_SplineData&) {} + virtual void addControlPoint(const DL_ControlPointData&) {} + virtual void addFitPoint(const DL_FitPointData&) {} + virtual void addKnot(const DL_KnotData&) {} + + virtual void addInsert(const DL_InsertData&) {} + + virtual void addMText(const DL_MTextData&) {} + virtual void addMTextChunk(const std::string&) {} + virtual void addText(const DL_TextData&) {} + virtual void addArcAlignedText(const DL_ArcAlignedTextData&) {} + virtual void addAttribute(const DL_AttributeData&) {} + + virtual void addDimAlign(const DL_DimensionData&, + const DL_DimAlignedData&) {} + virtual void addDimLinear(const DL_DimensionData&, + const DL_DimLinearData&) {} + virtual void addDimRadial(const DL_DimensionData&, + const DL_DimRadialData&) {} + virtual void addDimDiametric(const DL_DimensionData&, + const DL_DimDiametricData&) {} + virtual void addDimAngular(const DL_DimensionData&, + const DL_DimAngularData&) {} + virtual void addDimAngular3P(const DL_DimensionData&, + const DL_DimAngular3PData&) {} + virtual void addDimOrdinate(const DL_DimensionData&, + const DL_DimOrdinateData&) {} + virtual void addLeader(const DL_LeaderData&) {} + virtual void addLeaderVertex(const DL_LeaderVertexData&) {} + + virtual void addHatch(const DL_HatchData&) {} + + virtual void addTrace(const DL_TraceData&) {} + virtual void add3dFace(const DL_3dFaceData&) {} + virtual void addSolid(const DL_SolidData&) {} + + virtual void addImage(const DL_ImageData&) {} + virtual void linkImage(const DL_ImageDefData&) {} + virtual void addHatchLoop(const DL_HatchLoopData&) {} + virtual void addHatchEdge(const DL_HatchEdgeData&) {} + + virtual void addXRecord(const std::string&) {} + virtual void addXRecordString(int, const std::string&) {} + virtual void addXRecordReal(int, double) {} + virtual void addXRecordInt(int, int) {} + virtual void addXRecordBool(int, bool) {} + + virtual void addXDataApp(const std::string&) {} + virtual void addXDataString(int, const std::string&) {} + virtual void addXDataReal(int, double) {} + virtual void addXDataInt(int, int) {} + + virtual void addDictionary(const DL_DictionaryData&) {} + virtual void addDictionaryEntry(const DL_DictionaryEntryData&) {} + + virtual void endEntity() {} + + virtual void addComment(const std::string&) {} + + virtual void setVariableVector(const std::string&, double, double, double, int) {} + virtual void setVariableString(const std::string&, const std::string&, int) {} + virtual void setVariableInt(const std::string&, int, int) {} + virtual void setVariableDouble(const std::string&, double, int) {} +#ifdef DL_COMPAT + virtual void setVariableVector(const char*, double, double, double, int) {} + virtual void setVariableString(const char*, const char*, int) {} + virtual void setVariableInt(const char*, int, int) {} + virtual void setVariableDouble(const char*, double, int) {} + virtual void processCodeValuePair(unsigned int, char*) {} + virtual void addComment(const char*) {} + virtual void addMTextChunk(const char*) {} +#endif + virtual void endSequence() {} +}; + +#endif diff --git a/datafile/dxf/dxflib/dl_creationinterface.h b/datafile/dxf/dxflib/dl_creationinterface.h new file mode 100644 index 0000000..81bde52 --- /dev/null +++ b/datafile/dxf/dxflib/dl_creationinterface.h @@ -0,0 +1,369 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_CREATIONINTERFACE_H +#define DL_CREATIONINTERFACE_H + +#include "dl_global.h" + +#include + +#include "dl_attributes.h" +#include "dl_codes.h" +#include "dl_entities.h" +#include "dl_extrusion.h" + +/** + * Abstract class (interface) for the creation of new entities. + * Inherit your class which takes care of the entities in the + * processed DXF file from this interface. + * + * Double arrays passed to your implementation contain 3 double + * values for x, y, z coordinates unless stated differently. + * + * @author Andrew Mustun + */ +class DXFLIB_EXPORT DL_CreationInterface { +public: + DL_CreationInterface() { + extrusion = new DL_Extrusion; + } + virtual ~DL_CreationInterface() { + delete extrusion; + } + + /** + * Called for every code / value tuple of the DXF file. The complete DXF file + * contents can be handled by the implemetation of this function. + */ + virtual void processCodeValuePair(unsigned int groupCode, const std::string& groupValue) = 0; + + /** + * Called when a section (entity, table entry, etc.) is finished. + */ + virtual void endSection() = 0; + + /** + * Called for every layer. + */ + virtual void addLayer(const DL_LayerData& data) = 0; + + /** + * Called for every linetype. + */ + virtual void addLinetype(const DL_LinetypeData& data) = 0; + + /** + * Called for every dash in linetype pattern + */ + virtual void addLinetypeDash(double length) = 0; + + /** + * Called for every block. Note: all entities added after this + * command go into this block until endBlock() is called. + * + * @see endBlock() + */ + virtual void addBlock(const DL_BlockData& data) = 0; + + /** Called to end the current block */ + virtual void endBlock() = 0; + + /** Called for every text style */ + virtual void addTextStyle(const DL_StyleData& data) = 0; + + /** Called for every point */ + virtual void addPoint(const DL_PointData& data) = 0; + + /** Called for every line */ + virtual void addLine(const DL_LineData& data) = 0; + + /** Called for every xline */ + virtual void addXLine(const DL_XLineData& data) = 0; + + /** Called for every ray */ + virtual void addRay(const DL_RayData& data) = 0; + + /** Called for every arc */ + virtual void addArc(const DL_ArcData& data) = 0; + + /** Called for every circle */ + virtual void addCircle(const DL_CircleData& data) = 0; + + /** Called for every ellipse */ + virtual void addEllipse(const DL_EllipseData& data) = 0; + + /** Called for every polyline start */ + virtual void addPolyline(const DL_PolylineData& data) = 0; + + /** Called for every polyline vertex */ + virtual void addVertex(const DL_VertexData& data) = 0; + + /** Called for every spline */ + virtual void addSpline(const DL_SplineData& data) = 0; + + /** Called for every spline control point */ + virtual void addControlPoint(const DL_ControlPointData& data) = 0; + + /** Called for every spline fit point */ + virtual void addFitPoint(const DL_FitPointData& data) = 0; + + /** Called for every spline knot value */ + virtual void addKnot(const DL_KnotData& data) = 0; + + /** Called for every insert. */ + virtual void addInsert(const DL_InsertData& data) = 0; + + /** Called for every trace start */ + virtual void addTrace(const DL_TraceData& data) = 0; + + /** Called for every 3dface start */ + virtual void add3dFace(const DL_3dFaceData& data) = 0; + + /** Called for every solid start */ + virtual void addSolid(const DL_SolidData& data) = 0; + + + /** Called for every multi Text entity. */ + virtual void addMText(const DL_MTextData& data) = 0; + + /** + * Called for additional text chunks for MTEXT entities. + * The chunks come at 250 character in size each. Note that + * those chunks come before the actual MTEXT entity. + */ + virtual void addMTextChunk(const std::string& text) = 0; + + /** Called for every text entity. */ + virtual void addText(const DL_TextData& data) = 0; + + /** Called for every arc aligned text entity. */ + virtual void addArcAlignedText(const DL_ArcAlignedTextData& data) = 0; + + /** Called for every block Attribute entity. */ + virtual void addAttribute(const DL_AttributeData& data) = 0; + + /** + * Called for every aligned dimension entity. + */ + virtual void addDimAlign(const DL_DimensionData& data, + const DL_DimAlignedData& edata) = 0; + /** + * Called for every linear or rotated dimension entity. + */ + virtual void addDimLinear(const DL_DimensionData& data, + const DL_DimLinearData& edata) = 0; + + /** + * Called for every radial dimension entity. + */ + virtual void addDimRadial(const DL_DimensionData& data, + const DL_DimRadialData& edata) = 0; + + /** + * Called for every diametric dimension entity. + */ + virtual void addDimDiametric(const DL_DimensionData& data, + const DL_DimDiametricData& edata) = 0; + + /** + * Called for every angular dimension (2 lines version) entity. + */ + virtual void addDimAngular(const DL_DimensionData& data, + const DL_DimAngularData& edata) = 0; + + /** + * Called for every angular dimension (3 points version) entity. + */ + virtual void addDimAngular3P(const DL_DimensionData& data, + const DL_DimAngular3PData& edata) = 0; + + /** + * Called for every ordinate dimension entity. + */ + virtual void addDimOrdinate(const DL_DimensionData& data, + const DL_DimOrdinateData& edata) = 0; + + /** + * Called for every leader start. + */ + virtual void addLeader(const DL_LeaderData& data) = 0; + + /** + * Called for every leader vertex + */ + virtual void addLeaderVertex(const DL_LeaderVertexData& data) = 0; + + /** + * Called for every hatch entity. + */ + virtual void addHatch(const DL_HatchData& data) = 0; + + /** + * Called for every image entity. + */ + virtual void addImage(const DL_ImageData& data) = 0; + + /** + * Called for every image definition. + */ + virtual void linkImage(const DL_ImageDefData& data) = 0; + + /** + * Called for every hatch loop. + */ + virtual void addHatchLoop(const DL_HatchLoopData& data) = 0; + + /** + * Called for every hatch edge entity. + */ + virtual void addHatchEdge(const DL_HatchEdgeData& data) = 0; + + /** + * Called for every XRecord with the given handle. + */ + virtual void addXRecord(const std::string& handle) = 0; + + /** + * Called for XRecords of type string. + */ + virtual void addXRecordString(int code, const std::string& value) = 0; + + /** + * Called for XRecords of type double. + */ + virtual void addXRecordReal(int code, double value) = 0; + + /** + * Called for XRecords of type int. + */ + virtual void addXRecordInt(int code, int value) = 0; + + /** + * Called for XRecords of type bool. + */ + virtual void addXRecordBool(int code, bool value) = 0; + + /** + * Called for every beginning of an XData section of the given application. + */ + virtual void addXDataApp(const std::string& appId) = 0; + + /** + * Called for XData tuples. + */ + virtual void addXDataString(int code, const std::string& value) = 0; + + /** + * Called for XData tuples. + */ + virtual void addXDataReal(int code, double value) = 0; + + /** + * Called for XData tuples. + */ + virtual void addXDataInt(int code, int value) = 0; + + /** + * Called for dictionary objects. + */ + virtual void addDictionary(const DL_DictionaryData& data) = 0; + + /** + * Called for dictionary entries. + */ + virtual void addDictionaryEntry(const DL_DictionaryEntryData& data) = 0; + + /** + * Called after an entity has been completed. + */ + virtual void endEntity() = 0; + + /** + * Called for every comment in the DXF file (code 999). + */ + virtual void addComment(const std::string& comment) = 0; + + /** + * Called for every vector variable in the DXF file (e.g. "$EXTMIN"). + */ + virtual void setVariableVector(const std::string& key, double v1, double v2, double v3, int code) = 0; + + /** + * Called for every string variable in the DXF file (e.g. "$ACADVER"). + */ + virtual void setVariableString(const std::string& key, const std::string& value, int code) = 0; + + /** + * Called for every int variable in the DXF file (e.g. "$ACADMAINTVER"). + */ + virtual void setVariableInt(const std::string& key, int value, int code) = 0; + + /** + * Called for every double variable in the DXF file (e.g. "$DIMEXO"). + */ + virtual void setVariableDouble(const std::string& key, double value, int code) = 0; + +#ifdef DL_COMPAT + virtual void setVariableVector(const char* key, double v1, double v2, double v3, int code) = 0; + virtual void setVariableString(const char* key, const char* value, int code) = 0; + virtual void setVariableInt(const char* key, int value, int code) = 0; + virtual void setVariableDouble(const char* key, double value, int code) = 0; + virtual void processCodeValuePair(unsigned int groupCode, char* groupValue) = 0; + virtual void addComment(const char* comment) = 0; + virtual void addMTextChunk(const char* text) = 0; +#endif + + /** + * Called when a SEQEND occurs (when a POLYLINE or ATTRIB is done) + */ + virtual void endSequence() = 0; + + /** Sets the current attributes for entities. */ + void setAttributes(const DL_Attributes& attrib) { + attributes = attrib; + } + + /** @return the current attributes used for new entities. */ + DL_Attributes getAttributes() { + return attributes; + } + + /** Sets the current attributes for entities. */ + void setExtrusion(double dx, double dy, double dz, double elevation) { + extrusion->setDirection(dx, dy, dz); + extrusion->setElevation(elevation); + } + + /** @return the current attributes used for new entities. */ + DL_Extrusion* getExtrusion() { + return extrusion; + } + +protected: + DL_Attributes attributes; + DL_Extrusion *extrusion; +}; + +#endif diff --git a/datafile/dxf/dxflib/dl_dxf.cpp b/datafile/dxf/dxflib/dl_dxf.cpp new file mode 100644 index 0000000..4e74bce --- /dev/null +++ b/datafile/dxf/dxflib/dl_dxf.cpp @@ -0,0 +1,5332 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "dl_dxf.h" + +#include +#include +#include +#include +#include + +#include "dl_attributes.h" +#include "dl_codes.h" +#include "dl_creationadapter.h" +#include "dl_writer_ascii.h" + +#include "iostream" + +/** + * Default constructor. + */ +DL_Dxf::DL_Dxf() { + version = DL_VERSION_2000; + + vertices = NULL; + maxVertices = 0; + vertexIndex = 0; + + knots = NULL; + maxKnots = 0; + knotIndex = 0; + + weights = NULL; + weightIndex = 0; + + controlPoints = NULL; + maxControlPoints = 0; + controlPointIndex = 0; + + fitPoints = NULL; + maxFitPoints = 0; + fitPointIndex = 0; + + leaderVertices = NULL; + maxLeaderVertices = 0; + leaderVertexIndex = 0; +} + + + +/** + * Destructor. + */ +DL_Dxf::~DL_Dxf() { + if (vertices!=NULL) { + delete[] vertices; + } + if (knots!=NULL) { + delete[] knots; + } + if (controlPoints!=NULL) { + delete[] controlPoints; + } + if (fitPoints!=NULL) { + delete[] fitPoints; + } + if (weights!=NULL) { + delete[] weights; + } + if (leaderVertices!=NULL) { + delete[] leaderVertices; + } +} + + + +/** + * @brief Reads the given file and calls the appropriate functions in + * the given creation interface for every entity found in the file. + * + * @param file Input + * Path and name of file to read + * @param creationInterface + * Pointer to the class which takes care of the entities in the file. + * + * @retval true If \p file could be opened. + * @retval false If \p file could not be opened. + */ +bool DL_Dxf::in(const std::string& file, DL_CreationInterface* creationInterface) { + FILE *fp; + firstCall = true; + currentObjectType = DL_UNKNOWN; + + fp = fopen(file.c_str(), "rt"); + if (fp) { + std::locale oldLocale = std::locale::global(std::locale("C")); // use dot in numbers + while (readDxfGroups(fp, creationInterface)) {} + std::locale::global(oldLocale); + fclose(fp); + return true; + } + + return false; +} + + + +/** + * Reads a DXF file from an existing stream. + * + * @param stream The string stream. + * @param creationInterface + * Pointer to the class which takes care of the entities in the file. + * + * @retval true If \p file could be opened. + * @retval false If \p file could not be opened. + */ +bool DL_Dxf::in(std::stringstream& stream, + DL_CreationInterface* creationInterface) { + + if (stream.good()) { + firstCall=true; + currentObjectType = DL_UNKNOWN; + while (readDxfGroups(stream, creationInterface)) {} + return true; + } + return false; +} + + + +/** + * @brief Reads a group couplet from a DXF file. Calls another function + * to process it. + * + * A group couplet consists of two lines that represent a single + * piece of data. An integer constant on the first line indicates + * the type of data. The value is on the next line.\n + * + * This function reads a couplet, determines the type of data, and + * passes the value to the the appropriate handler function of + * \p creationInterface.\n + * + * \p fp is advanced so that the next call to \p readDXFGroups() reads + * the next couplet in the file. + * + * @param fp Handle of input file + * @param creationInterface Handle of class which processes entities + * in the file + * + * @retval true If EOF not reached. + * @retval false If EOF reached. + */ +bool DL_Dxf::readDxfGroups(FILE *fp, DL_CreationInterface* creationInterface) { + + static int line = 1; + + // Read one group of the DXF file and strip the lines: + if (DL_Dxf::getStrippedLine(groupCodeTmp, DL_DXF_MAXLINE, fp) && + DL_Dxf::getStrippedLine(groupValue, DL_DXF_MAXLINE, fp, false) ) { + + groupCode = (unsigned int)toInt(groupCodeTmp); + + creationInterface->processCodeValuePair(groupCode, groupValue); + line+=2; + processDXFGroup(creationInterface, groupCode, groupValue); + } + + return !feof(fp); +} + + + +/** + * Same as above but for stringstreams. + */ +bool DL_Dxf::readDxfGroups(std::stringstream& stream, + DL_CreationInterface* creationInterface) { + + static int line = 1; + + // Read one group of the DXF file and chop the lines: + if (DL_Dxf::getStrippedLine(groupCodeTmp, DL_DXF_MAXLINE, stream) && + DL_Dxf::getStrippedLine(groupValue, DL_DXF_MAXLINE, stream, false) ) { + + groupCode = (unsigned int)toInt(groupCodeTmp); + + line+=2; + processDXFGroup(creationInterface, groupCode, groupValue); + } + return !stream.eof(); +} + + + +/** + * @brief Reads line from file & strips whitespace at start and newline + * at end. + * + * @param s Output\n + * Pointer to character array that chopped line will be returned in. + * @param size Size of \p s. (Including space for NULL.) + * @param fp Input\n + * Handle of input file. + * + * @retval true if line could be read + * @retval false if \p fp is already at end of file + * + * @todo Change function to use safer FreeBSD strl* functions + * @todo Is it a problem if line is blank (i.e., newline only)? + * Then, when function returns, (s==NULL). + */ +bool DL_Dxf::getStrippedLine(std::string& s, unsigned int size, FILE *fp, bool stripSpace) { + if (!feof(fp)) { + // The whole line in the file. Includes space for NULL. + char* wholeLine = new char[size]; + // Only the useful part of the line + char* line; + + line = fgets(wholeLine, size, fp); + + if (line!=NULL && line[0] != '\0') { // Evaluates to fgets() retval + // line == wholeLine at this point. + // Both guaranteed to be NULL terminated. + + // Strip leading whitespace and trailing CR/LF. + stripWhiteSpace(&line, stripSpace); + + s = line; + assert(size > s.length()); + } + + delete[] wholeLine; // Done with wholeLine + + return true; + } else { + s = ""; + return false; + } +} + + + +/** + * Same as above but for stringstreams. + */ +bool DL_Dxf::getStrippedLine(std::string &s, unsigned int size, + std::stringstream& stream, bool stripSpace) { + + if (!stream.eof()) { + // Only the useful part of the line + char* line = new char[size+1]; + char* oriLine = line; + stream.getline(line, size); + stripWhiteSpace(&line, stripSpace); + s = line; + assert(size > s.length()); + delete[] oriLine; + return true; + } else { + s[0] = '\0'; + return false; + } +} + + + +/** + * @brief Strips leading whitespace and trailing Carriage Return (CR) + * and Line Feed (LF) from NULL terminated string. + * + * @param s Input and output. + * NULL terminates string. + * + * @retval true if \p s is non-NULL + * @retval false if \p s is NULL + */ +bool DL_Dxf::stripWhiteSpace(char** s, bool stripSpace) { + // last non-NULL char: + int lastChar = strlen(*s) - 1; + + // Is last character CR or LF? + while ( (lastChar >= 0) && + (((*s)[lastChar] == 10) || ((*s)[lastChar] == 13) || + (stripSpace && ((*s)[lastChar] == ' ' || ((*s)[lastChar] == '\t')))) ) { + (*s)[lastChar] = '\0'; + lastChar--; + } + + // Skip whitespace, excluding \n, at beginning of line + if (stripSpace) { + while ((*s)[0]==' ' || (*s)[0]=='\t') { + ++(*s); + } + } + + return ((*s) ? true : false); +} + + + +/** + * Processes a group (pair of group code and value). + * + * @param creationInterface Handle to class that creates entities and + * other CAD data from DXF group codes + * + * @param groupCode Constant indicating the data type of the group. + * @param groupValue The data value. + * + * @retval true if done processing current entity and new entity begun + * @retval false if not done processing current entity +*/ +bool DL_Dxf::processDXFGroup(DL_CreationInterface* creationInterface, + int groupCode, const std::string& groupValue) { + + //printf("%d\n", groupCode); + //printf("%s\n", groupValue.c_str()); + + // Init values on first call + if (firstCall) { + settingValue[0] = '\0'; + firstCall=false; + } + + // Indicates comment or dxflib version: + if (groupCode==999) { + if (!groupValue.empty()) { + if (groupValue.substr(0, 6)=="dxflib") { + libVersion = getLibVersion(groupValue.substr(7)); + } + + addComment(creationInterface, groupValue); + } + } + + // Indicates start of new entity or variable: + else if (groupCode==0 || groupCode==9) { + // If new entity is encountered, the last one is complete. + // Prepare default attributes for next entity: + std::string layer = getStringValue(8, "0"); + + int width; + // Compatibility with qcad1: + if (hasValue(39) && !hasValue(370)) { + width = getIntValue(39, -1); + } + // since autocad 2002: + else if (hasValue(370)) { + width = getIntValue(370, -1); + } + // default to BYLAYER: + else { + width = -1; + } + + int color; + color = getIntValue(62, 256); + int color24; + color24 = getIntValue(420, -1); + int handle; + handle = getInt16Value(5, -1); + + std::string linetype = getStringValue(6, "BYLAYER"); + + attrib = DL_Attributes(layer, // layer + color, // color + color24, // 24 bit color + width, // width + linetype, // linetype + handle); // handle + attrib.setInPaperSpace((bool)getIntValue(67, 0)); + attrib.setLinetypeScale(getRealValue(48, 1.0)); + creationInterface->setAttributes(attrib); + + int elevationGroupCode=30; + if (currentObjectType==DL_ENTITY_LWPOLYLINE ) { + // see lwpolyline group codes reference + elevationGroupCode=38; + } + else { + // see polyline group codes reference + elevationGroupCode=30; + } + + creationInterface->setExtrusion(getRealValue(210, 0.0), + getRealValue(220, 0.0), + getRealValue(230, 1.0), + getRealValue(elevationGroupCode, 0.0)); + + // Add the previously parsed entity via creationInterface + switch (currentObjectType) { + case DL_SETTING: + addSetting(creationInterface); + break; + + case DL_LAYER: + addLayer(creationInterface); + break; + + case DL_LINETYPE: + addLinetype(creationInterface); + break; + + case DL_BLOCK: + addBlock(creationInterface); + break; + + case DL_ENDBLK: + endBlock(creationInterface); + break; + + case DL_STYLE: + addTextStyle(creationInterface); + break; + + case DL_ENTITY_POINT: + addPoint(creationInterface); + break; + + case DL_ENTITY_LINE: + addLine(creationInterface); + break; + + case DL_ENTITY_XLINE: + addXLine(creationInterface); + break; + + case DL_ENTITY_RAY: + addRay(creationInterface); + break; + + case DL_ENTITY_POLYLINE: + case DL_ENTITY_LWPOLYLINE: + addPolyline(creationInterface); + break; + + case DL_ENTITY_VERTEX: + addVertex(creationInterface); + break; + + case DL_ENTITY_SPLINE: + addSpline(creationInterface); + break; + + case DL_ENTITY_ARC: + addArc(creationInterface); + break; + + case DL_ENTITY_CIRCLE: + addCircle(creationInterface); + break; + + case DL_ENTITY_ELLIPSE: + addEllipse(creationInterface); + break; + + case DL_ENTITY_INSERT: + addInsert(creationInterface); + break; + + case DL_ENTITY_MTEXT: + addMText(creationInterface); + break; + + case DL_ENTITY_TEXT: + addText(creationInterface); + break; + + case DL_ENTITY_ARCALIGNEDTEXT: + addArcAlignedText(creationInterface); + break; + + case DL_ENTITY_ATTRIB: + addAttribute(creationInterface); + break; + + case DL_ENTITY_DIMENSION: { + int type = (getIntValue(70, 0)&0x07); + + switch (type) { + case 0: + addDimLinear(creationInterface); + break; + + case 1: + addDimAligned(creationInterface); + break; + + case 2: + addDimAngular(creationInterface); + break; + + case 3: + addDimDiametric(creationInterface); + break; + + case 4: + addDimRadial(creationInterface); + break; + + case 5: + addDimAngular3P(creationInterface); + break; + + case 6: + addDimOrdinate(creationInterface); + break; + + default: + break; + } + } + break; + + case DL_ENTITY_LEADER: + addLeader(creationInterface); + break; + + case DL_ENTITY_HATCH: + //addHatch(creationInterface); + handleHatchData(creationInterface); + break; + + case DL_ENTITY_IMAGE: + addImage(creationInterface); + break; + + case DL_ENTITY_IMAGEDEF: + addImageDef(creationInterface); + break; + + case DL_ENTITY_TRACE: + addTrace(creationInterface); + break; + + case DL_ENTITY_3DFACE: + add3dFace(creationInterface); + break; + + case DL_ENTITY_SOLID: + addSolid(creationInterface); + break; + + case DL_ENTITY_SEQEND: + endSequence(creationInterface); + break; + + default: + break; + } + + creationInterface->endSection(); + + // reset all values (they are not persistent and only this + // way we can set defaults for omitted values) +// for (int i=0; iaddComment(comment); +} + +void DL_Dxf::addDictionary(DL_CreationInterface* creationInterface) { + creationInterface->addDictionary(DL_DictionaryData(getStringValue(5, ""))); +} + +void DL_Dxf::addDictionaryEntry(DL_CreationInterface* creationInterface) { + creationInterface->addDictionaryEntry(DL_DictionaryEntryData(getStringValue(3, ""), getStringValue(350, ""))); +} + + + +/** + * Adds a variable from the DXF file. + */ +void DL_Dxf::addSetting(DL_CreationInterface* creationInterface) { + int c = -1; + std::map::iterator it = values.begin(); + if (it!=values.end()) { + c = it->first; + } +// for (int i=0; i<=380; ++i) { +// if (values[i][0]!='\0') { +// c = i; +// break; +// } +// } + + // string + if (c>=0 && c<=9) { + creationInterface->setVariableString(settingKey, values[c], c); + #ifdef DL_COMPAT + // backwards compatibility: + creationInterface->setVariableString(settingKey.c_str(), values[c].c_str(), c); + #endif + } + // vector + else if (c>=10 && c<=39) { + if (c==10) { + creationInterface->setVariableVector( + settingKey, + getRealValue(c, 0.0), + getRealValue(c+10, 0.0), + getRealValue(c+20, 0.0), + c); + } + } + // double + else if (c>=40 && c<=59) { + creationInterface->setVariableDouble(settingKey, getRealValue(c, 0.0), c); + } + // int + else if (c>=60 && c<=99) { + creationInterface->setVariableInt(settingKey, getIntValue(c, 0), c); + } + // misc + else if (c>=0) { + creationInterface->setVariableString(settingKey, getStringValue(c, ""), c); + } +} + + + +/** + * Adds a layer that was read from the file via the creation interface. + */ +void DL_Dxf::addLayer(DL_CreationInterface* creationInterface) { + // correct some invalid attributes for layers: + attrib = creationInterface->getAttributes(); + if (attrib.getColor()==256 || attrib.getColor()==0) { + attrib.setColor(7); + } + if (attrib.getWidth()<0) { + attrib.setWidth(1); + } + + std::string linetype = attrib.getLinetype(); + std::transform(linetype.begin(), linetype.end(), linetype.begin(), ::toupper); + if (linetype=="BYLAYER" || linetype=="BYBLOCK") { + attrib.setLinetype("CONTINUOUS"); + } + + // add layer + std::string name = getStringValue(2, ""); + if (name.length()==0) { + return; + } + + creationInterface->addLayer(DL_LayerData(name, getIntValue(70, 0))); +} + +/** + * Adds a linetype that was read from the file via the creation interface. + */ +void DL_Dxf::addLinetype(DL_CreationInterface* creationInterface) { + std::string name = getStringValue(2, ""); + if (name.length()==0) { + return; + } + int numDashes = getIntValue(73, 0); + //double dashes[numDashes]; + + DL_LinetypeData d( + // name: + name, + // description: + getStringValue(3, ""), + // flags + getIntValue(70, 0), + // number of dashes: + numDashes, + // pattern length: + getRealValue(40, 0.0) + // pattern: + //dashes + ); + + if (name != "By Layer" && name != "By Block" && name != "BYLAYER" && name != "BYBLOCK") { + creationInterface->addLinetype(d); + } +} + +/** + * Handles all dashes in linetype pattern. + */ +bool DL_Dxf::handleLinetypeData(DL_CreationInterface* creationInterface) { + if (groupCode == 49) { + creationInterface->addLinetypeDash(toReal(groupValue)); + return true; + } + + return false; +} + + +/** + * Adds a block that was read from the file via the creation interface. + */ +void DL_Dxf::addBlock(DL_CreationInterface* creationInterface) { + std::string name = getStringValue(2, ""); + if (name.length()==0) { + return; + } + + DL_BlockData d( + // Name: + name, + // flags: + getIntValue(70, 0), + // base point: + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0)); + + creationInterface->addBlock(d); +} + + + +/** + * Ends a block that was read from the file via the creation interface. + */ +void DL_Dxf::endBlock(DL_CreationInterface* creationInterface) { + creationInterface->endBlock(); +} + + + +void DL_Dxf::addTextStyle(DL_CreationInterface* creationInterface) { + std::string name = getStringValue(2, ""); + if (name.length()==0) { + return; + } + + DL_StyleData d( + // name: + name, + // flags + getIntValue(70, 0), + // fixed text heigth: + getRealValue(40, 0.0), + // width factor: + getRealValue(41, 0.0), + // oblique angle: + getRealValue(50, 0.0), + // text generation flags: + getIntValue(71, 0), + // last height used: + getRealValue(42, 0.0), + // primart font file: + getStringValue(3, ""), + // big font file: + getStringValue(4, "") + ); + creationInterface->addTextStyle(d); +} + + +/** + * Adds a point entity that was read from the file via the creation interface. + */ +void DL_Dxf::addPoint(DL_CreationInterface* creationInterface) { + DL_PointData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0)); + creationInterface->addPoint(d); +} + + + +/** + * Adds a line entity that was read from the file via the creation interface. + */ +void DL_Dxf::addLine(DL_CreationInterface* creationInterface) { + DL_LineData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0)); + + creationInterface->addLine(d); +} + +/** + * Adds an xline entity that was read from the file via the creation interface. + */ +void DL_Dxf::addXLine(DL_CreationInterface* creationInterface) { + DL_XLineData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0)); + + creationInterface->addXLine(d); +} + +/** + * Adds a ray entity that was read from the file via the creation interface. + */ +void DL_Dxf::addRay(DL_CreationInterface* creationInterface) { + DL_RayData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0)); + + creationInterface->addRay(d); +} + + + +/** + * Adds a polyline entity that was read from the file via the creation interface. + */ +void DL_Dxf::addPolyline(DL_CreationInterface* creationInterface) { + DL_PolylineData pd(maxVertices, getIntValue(71, 0), getIntValue(72, 0), getIntValue(70, 0), getRealValue(38, 0)); + creationInterface->addPolyline(pd); + + maxVertices = std::min(maxVertices, vertexIndex+1); + + if (currentObjectType==DL_ENTITY_LWPOLYLINE) { + for (int i=0; iaddVertex(d); + } + creationInterface->endEntity(); + } +} + + + +/** + * Adds a polyline vertex entity that was read from the file + * via the creation interface. + */ +void DL_Dxf::addVertex(DL_CreationInterface* creationInterface) { + + // vertex defines a face of the mesh if its vertex flags group has the + // 128 bit set but not the 64 bit. 10, 20, 30 are irrelevant and set to + // 0 in this case + if ((getIntValue(70, 0)&128) && !(getIntValue(70, 0)&64)) { + return; + } + + DL_VertexData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(42, 0.0)); + + creationInterface->addVertex(d); +} + + +/** + * Adds a spline entity that was read from the file via the creation interface. + */ +void DL_Dxf::addSpline(DL_CreationInterface* creationInterface) { + DL_SplineData sd(getIntValue(71, 3), + maxKnots, + maxControlPoints, + maxFitPoints, + getIntValue(70, 4)); + + sd.tangentStartX = getRealValue(12, 0.0); + sd.tangentStartY = getRealValue(22, 0.0); + sd.tangentStartZ = getRealValue(32, 0.0); + sd.tangentEndX = getRealValue(13, 0.0); + sd.tangentEndY = getRealValue(23, 0.0); + sd.tangentEndZ = getRealValue(33, 0.0); + + creationInterface->addSpline(sd); + + int i; + for (i=0; iaddControlPoint(d); + } + for (i=0; iaddFitPoint(d); + } + for (i=0; iaddKnot(k); + } + creationInterface->endEntity(); +} + + + +/** + * Adds an arc entity that was read from the file via the creation interface. + */ +void DL_Dxf::addArc(DL_CreationInterface* creationInterface) { + DL_ArcData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(40, 0.0), + getRealValue(50, 0.0), + getRealValue(51, 0.0)); + + creationInterface->addArc(d); +} + + + +/** + * Adds a circle entity that was read from the file via the creation interface. + */ +void DL_Dxf::addCircle(DL_CreationInterface* creationInterface) { + DL_CircleData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(40, 0.0)); + + creationInterface->addCircle(d); +} + + + +/** + * Adds an ellipse entity that was read from the file via the creation interface. + */ +void DL_Dxf::addEllipse(DL_CreationInterface* creationInterface) { + DL_EllipseData d(getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0), + getRealValue(40, 1.0), + getRealValue(41, 0.0), + getRealValue(42, 2*M_PI)); + + creationInterface->addEllipse(d); +} + + + +/** + * Adds an insert entity that was read from the file via the creation interface. + */ +void DL_Dxf::addInsert(DL_CreationInterface* creationInterface) { + //printf("addInsert\n"); + //printf("code 50: %s\n", values[50]); + //printf("code 50 length: %d\n", strlen(values[50])); + //printf("code 50:\n"); + //getRealValue(50, 0.0); + + std::string name = getStringValue(2, ""); + if (name.length()==0) { + return; + } + + DL_InsertData d(name, + // insertion point + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + // scale: + getRealValue(41, 1.0), + getRealValue(42, 1.0), + getRealValue(43, 1.0), + // angle (deg): + getRealValue(50, 0.0), + // cols / rows: + getIntValue(70, 1), + getIntValue(71, 1), + // spacing: + getRealValue(44, 0.0), + getRealValue(45, 0.0)); + + creationInterface->addInsert(d); +} + + + +/** + * Adds a trace entity (4 edge closed polyline) that was read from the file via the creation interface. + * + * @author AHM + */ +void DL_Dxf::addTrace(DL_CreationInterface* creationInterface) { + DL_TraceData td; + + for (int k = 0; k < 4; k++) { + td.x[k] = getRealValue(10 + k, 0.0); + td.y[k] = getRealValue(20 + k, 0.0); + td.z[k] = getRealValue(30 + k, 0.0); + } + creationInterface->addTrace(td); +} + + + +/** + * Adds a 3dface entity that was read from the file via the creation interface. + */ +void DL_Dxf::add3dFace(DL_CreationInterface* creationInterface) { + DL_3dFaceData td; + + for (int k = 0; k < 4; k++) { + td.x[k] = getRealValue(10 + k, 0.0); + td.y[k] = getRealValue(20 + k, 0.0); + td.z[k] = getRealValue(30 + k, 0.0); + } + creationInterface->add3dFace(td); +} + + + +/** + * Adds a solid entity (filled trace) that was read from the file via the creation interface. + * + * @author AHM + */ +void DL_Dxf::addSolid(DL_CreationInterface* creationInterface) { + DL_SolidData sd; + + for (int k = 0; k < 4; k++) { + sd.x[k] = getRealValue(10 + k, 0.0); + sd.y[k] = getRealValue(20 + k, 0.0); + sd.z[k] = getRealValue(30 + k, 0.0); + } + creationInterface->addSolid(sd); +} + + +/** + * Adds an MText entity that was read from the file via the creation interface. + */ +void DL_Dxf::addMText(DL_CreationInterface* creationInterface) { + double angle = 0.0; + + if (hasValue(50)) { + if (libVersion<=0x02000200) { + // wrong but compatible with dxflib <=2.0.2.0 (angle stored in rad): + angle = getRealValue(50, 0.0); + } else { + angle = (getRealValue(50, 0.0)*2*M_PI)/360.0; + } + } else if (hasValue(11) && hasValue(21)) { + double x = getRealValue(11, 0.0); + double y = getRealValue(21, 0.0); + + if (fabs(x)<1.0e-6) { + if (y>0.0) { + angle = M_PI/2.0; + } else { + angle = M_PI/2.0*3.0; + } + } else { + angle = atan(y/x); + } + } + + DL_MTextData d( + // insertion point + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + // X direction vector + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0), + // height + getRealValue(40, 2.5), + // width + getRealValue(41, 0.0), + // attachment point + getIntValue(71, 1), + // drawing direction + getIntValue(72, 1), + // line spacing style + getIntValue(73, 1), + // line spacing factor + getRealValue(44, 1.0), + // text + getStringValue(1, ""), + // style + getStringValue(7, ""), + // angle + angle); + creationInterface->addMText(d); +} + +/** + * Handles all XRecord data. + */ +bool DL_Dxf::handleXRecordData(DL_CreationInterface* creationInterface) { + if (groupCode==105) { + return false; + } + + if (groupCode==5) { + creationInterface->addXRecord(groupValue); + return true; + } + + if (groupCode==280) { + xRecordValues = true; + return true; + } + + if (!xRecordValues) { + return false; + } + + // string: + if (groupCode<=9 || + groupCode==100 || groupCode==102 || groupCode==105 || + (groupCode>=300 && groupCode<=369) || + (groupCode>=1000 && groupCode<=1009)) { + + creationInterface->addXRecordString(groupCode, groupValue); + return true; + } + + // int: + else if ((groupCode>=60 && groupCode<=99) || (groupCode>=160 && groupCode<=179) || (groupCode>=270 && groupCode<=289)) { + creationInterface->addXRecordInt(groupCode, toInt(groupValue)); + return true; + } + + // bool: + else if (groupCode>=290 && groupCode<=299) { + creationInterface->addXRecordBool(groupCode, toBool(groupValue)); + return true; + } + + // double: + else if ((groupCode>=10 && groupCode<=59) || (groupCode>=110 && groupCode<=149) || (groupCode>=210 && groupCode<=239)) { + creationInterface->addXRecordReal(groupCode, toReal(groupValue)); + return true; + } + + return false; +} + +/** + * Handles all dictionary data. + */ +bool DL_Dxf::handleDictionaryData(DL_CreationInterface* creationInterface) { + if (groupCode==3) { + return true; + } + + if (groupCode==5) { + creationInterface->addDictionary(DL_DictionaryData(groupValue)); + return true; + } + + if (groupCode==350) { + creationInterface->addDictionaryEntry(DL_DictionaryEntryData(getStringValue(3, ""), groupValue)); + return true; + } + return false; +} + + + +/** + * Handles XData for all object types. + */ +bool DL_Dxf::handleXData(DL_CreationInterface* creationInterface) { + if (groupCode==1001) { + creationInterface->addXDataApp(groupValue); + return true; + } + else if (groupCode>=1000 && groupCode<=1009) { + creationInterface->addXDataString(groupCode, groupValue); + return true; + } + else if (groupCode>=1010 && groupCode<=1059) { + creationInterface->addXDataReal(groupCode, toReal(groupValue)); + return true; + } + else if (groupCode>=1060 && groupCode<=1070) { + creationInterface->addXDataInt(groupCode, toInt(groupValue)); + return true; + } + else if (groupCode==1071) { + creationInterface->addXDataInt(groupCode, toInt(groupValue)); + return true; + } + + return false; +} + +/** + * Handles additional MText data. + */ +bool DL_Dxf::handleMTextData(DL_CreationInterface* creationInterface) { + // Special handling of text chunks for MTEXT entities: + if (groupCode==3) { + creationInterface->addMTextChunk(groupValue); + return true; + } + + return false; +} + +/** + * Handles additional polyline data. + */ +bool DL_Dxf::handleLWPolylineData(DL_CreationInterface* /*creationInterface*/) { + // Allocate LWPolyline vertices (group code 90): + if (groupCode==90) { + maxVertices = toInt(groupValue); + if (maxVertices>0) { + if (vertices!=NULL) { + delete[] vertices; + } + vertices = new double[4*maxVertices]; + for (int i=0; i=0 && vertexIndex0) { + if (knots!=NULL) { + delete[] knots; + } + knots = new double[maxKnots]; + for (int i=0; i0) { + if (controlPoints!=NULL) { + delete[] controlPoints; + } + if (weights!=NULL) { + delete[] weights; + } + controlPoints = new double[3*maxControlPoints]; + weights = new double[maxControlPoints]; + for (int i=0; i0) { + if (fitPoints!=NULL) { + delete[] fitPoints; + } + fitPoints = new double[3*maxFitPoints]; + for (int i=0; i=0 && controlPointIndex=0 && fitPointIndex=0 && weightIndex0) { + if (leaderVertices!=NULL) { + delete[] leaderVertices; + } + leaderVertices = new double[3*maxLeaderVertices]; + for (int i=0; i=0 && + leaderVertexIndexaddText(d); +} + + +/** + * Adds an arc aligned text entity that was read from the file via the creation interface. + */ +void DL_Dxf::addArcAlignedText(DL_CreationInterface* creationInterface) { + DL_ArcAlignedTextData d; + d.text = getStringValue(1, ""); + d.font = getStringValue(2, ""); + d.style = getStringValue(7, ""); + d.cx = getRealValue(10, 0.0); + d.cy = getRealValue(20, 0.0); + d.cz = getRealValue(30, 0.0); + d.radius = getRealValue(40, 0.0); + d.xScaleFactor = getRealValue(41, 0.0); + d.height = getRealValue(42, 0.0); + d.spacing = getRealValue(43, 0.0); + d.offset = getRealValue(44, 0.0); + d.rightOffset = getRealValue(45, 0.0); + d.leftOffset = getRealValue(46, 0.0); + d.startAngle = getRealValue(50, 0.0); + d.endAngle = getRealValue(51, 0.0); + d.reversedCharacterOrder = getIntValue(70, 0); + d.direction = getIntValue(71, 0); + d.alignment = getIntValue(72, 0); + d.side = getIntValue(73, 0); + d.bold = getIntValue(74, 0); + d.italic = getIntValue(75, 0); + d.underline = getIntValue(76, 0); + d.characerSet = getIntValue(77, 0); + d.pitch = getIntValue(78, 0); + d.shxFont = getIntValue(79, 0); + d.wizard = getIntValue(280, 0); + d.arcHandle = getIntValue(330, 0); + + creationInterface->addArcAlignedText(d); +} + + + +/** + * Adds an attrib entity that was read from the file via the creation interface. + * @todo add attrib instead of normal text + */ +void DL_Dxf::addAttribute(DL_CreationInterface* creationInterface) { + DL_AttributeData d( + // insertion point + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + // alignment point + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0), + // height + getRealValue(40, 2.5), + // x scale + getRealValue(41, 1.0), + // generation flags + getIntValue(71, 0), + // h just + getIntValue(72, 0), + // v just + getIntValue(74, 0), + // tag + getStringValue(2, ""), + // text + getStringValue(1, ""), + // style + getStringValue(7, ""), + // angle + (getRealValue(50, 0.0)*2*M_PI)/360.0); + + creationInterface->addAttribute(d); +} + + + +/** + * @return dimension data from current values. + */ +DL_DimensionData DL_Dxf::getDimData() { + // generic dimension data: + return DL_DimensionData( + // def point + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + // text middle point + getRealValue(11, 0.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0), + // type + getIntValue(70, 0), + // attachment point + getIntValue(71, 5), + // line sp. style + getIntValue(72, 1), + // line sp. factor + getRealValue(41, 1.0), + // text + getStringValue(1, ""), + // style + getStringValue(3, ""), + // angle + getRealValue(53, 0.0)); +} + + + +/** + * Adds a linear dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimLinear(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // horizontal / vertical / rotated dimension: + DL_DimLinearData dl( + // definition point 1 + getRealValue(13, 0.0), + getRealValue(23, 0.0), + getRealValue(33, 0.0), + // definition point 2 + getRealValue(14, 0.0), + getRealValue(24, 0.0), + getRealValue(34, 0.0), + // angle + getRealValue(50, 0.0), + // oblique + getRealValue(52, 0.0)); + creationInterface->addDimLinear(d, dl); +} + + + +/** + * Adds an aligned dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimAligned(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // aligned dimension: + DL_DimAlignedData da( + // extension point 1 + getRealValue(13, 0.0), + getRealValue(23, 0.0), + getRealValue(33, 0.0), + // extension point 2 + getRealValue(14, 0.0), + getRealValue(24, 0.0), + getRealValue(34, 0.0)); + creationInterface->addDimAlign(d, da); +} + + + +/** + * Adds a radial dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimRadial(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + DL_DimRadialData dr( + // definition point + getRealValue(15, 0.0), + getRealValue(25, 0.0), + getRealValue(35, 0.0), + // leader length: + getRealValue(40, 0.0)); + creationInterface->addDimRadial(d, dr); +} + + + +/** + * Adds a diametric dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimDiametric(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // diametric dimension: + DL_DimDiametricData dr( + // definition point + getRealValue(15, 0.0), + getRealValue(25, 0.0), + getRealValue(35, 0.0), + // leader length: + getRealValue(40, 0.0)); + creationInterface->addDimDiametric(d, dr); +} + + + +/** + * Adds an angular dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimAngular(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // angular dimension: + DL_DimAngularData da( + // definition point 1 + getRealValue(13, 0.0), + getRealValue(23, 0.0), + getRealValue(33, 0.0), + // definition point 2 + getRealValue(14, 0.0), + getRealValue(24, 0.0), + getRealValue(34, 0.0), + // definition point 3 + getRealValue(15, 0.0), + getRealValue(25, 0.0), + getRealValue(35, 0.0), + // definition point 4 + getRealValue(16, 0.0), + getRealValue(26, 0.0), + getRealValue(36, 0.0)); + creationInterface->addDimAngular(d, da); +} + + +/** + * Adds an angular dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimAngular3P(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // angular dimension (3P): + DL_DimAngular3PData da( + // definition point 1 + getRealValue(13, 0.0), + getRealValue(23, 0.0), + getRealValue(33, 0.0), + // definition point 2 + getRealValue(14, 0.0), + getRealValue(24, 0.0), + getRealValue(34, 0.0), + // definition point 3 + getRealValue(15, 0.0), + getRealValue(25, 0.0), + getRealValue(35, 0.0)); + creationInterface->addDimAngular3P(d, da); +} + + + +/** + * Adds an ordinate dimension entity that was read from the file via the creation interface. + */ +void DL_Dxf::addDimOrdinate(DL_CreationInterface* creationInterface) { + DL_DimensionData d = getDimData(); + + // ordinate dimension: + DL_DimOrdinateData dl( + // definition point 1 + getRealValue(13, 0.0), + getRealValue(23, 0.0), + getRealValue(33, 0.0), + // definition point 2 + getRealValue(14, 0.0), + getRealValue(24, 0.0), + getRealValue(34, 0.0), + (getIntValue(70, 0)&64)==64 // true: X-type, false: Y-type + ); + creationInterface->addDimOrdinate(d, dl); +} + + + +/** + * Adds a leader entity that was read from the file via the creation interface. + */ +void DL_Dxf::addLeader(DL_CreationInterface* creationInterface) { + // leader (arrow) + DL_LeaderData le( + // arrow head flag + getIntValue(71, 1), + // leader path type + getIntValue(72, 0), + // Leader creation flag + getIntValue(73, 3), + // Hookline direction flag + getIntValue(74, 1), + // Hookline flag + getIntValue(75, 0), + // Text annotation height + getRealValue(40, 1.0), + // Text annotation width + getRealValue(41, 1.0), + // Number of vertices in leader + getIntValue(76, 0) + ); + creationInterface->addLeader(le); + + for (int i=0; iaddLeaderVertex(d); + } + creationInterface->endEntity(); +} + +/** + * Adds a hatch entity that was read from the file via the creation interface. + */ +void DL_Dxf::addHatch(DL_CreationInterface* creationInterface) { + DL_HatchData hd(getIntValue(91, 1), + getIntValue(70, 0), + getRealValue(41, 1.0), + getRealValue(52, 0.0), + getStringValue(2, "")); + + creationInterface->addHatch(hd); + + for (unsigned int i=0; iaddHatchLoop(DL_HatchLoopData(hatchEdges[i].size())); + for (unsigned int k=0; kaddHatchEdge(DL_HatchEdgeData(hatchEdges[i][k])); + } + } + + creationInterface->endEntity(); +} + +void DL_Dxf::addHatchLoop() { + addHatchEdge(); + hatchEdges.push_back(std::vector()); +} + +void DL_Dxf::addHatchEdge() { + if (hatchEdge.defined) { + if (hatchEdges.size()>0) { + hatchEdges.back().push_back(hatchEdge); + } + hatchEdge = DL_HatchEdgeData(); + } +} + +/** + * Handles all hatch data. + */ +bool DL_Dxf::handleHatchData(DL_CreationInterface* creationInterface) { + // New polyline loop, group code 92 + // or new loop with individual edges, group code 93 + if (groupCode==92 || groupCode==93) { + if (firstHatchLoop) { + hatchEdges.clear(); + firstHatchLoop = false; + } + if (groupCode==92 && (toInt(groupValue)&2)==2) { + addHatchLoop(); + } + if (groupCode==93) { + addHatchLoop(); + } + return true; + } + + // New hatch edge or new section / entity: add last hatch edge: + if (groupCode==72 || groupCode==0 || groupCode==78 || groupCode==98) { + // polyline boundaries use code 72 for bulge flag: + if (groupCode!=72 || (getIntValue(92, 0)&2)==0) { + addHatchEdge(); + } + + if (groupCode==0 /*|| groupCode==78*/) { + addHatch(creationInterface); + } + else { + hatchEdge.type = toInt(groupValue); + } + return true; + } + + // polyline boundary: + if ((getIntValue(92, 0)&2)==2) { + switch (groupCode) { + case 10: + hatchEdge.type = 0; + hatchEdge.vertices.push_back(std::vector()); + hatchEdge.vertices.back().push_back(toReal(groupValue)); + return true; + case 20: + if (!hatchEdge.vertices.empty()) { + hatchEdge.vertices.back().push_back(toReal(groupValue)); + hatchEdge.defined = true; + } + return true; + case 42: + if (!hatchEdge.vertices.empty()) { + hatchEdge.vertices.back().push_back(toReal(groupValue)); + hatchEdge.defined = true; + } + return true; + } + } + else { + // Line edge: + if (hatchEdge.type==1) { + switch (groupCode) { + case 10: + hatchEdge.x1 = toReal(groupValue); + return true; + case 20: + hatchEdge.y1 = toReal(groupValue); + return true; + case 11: + hatchEdge.x2 = toReal(groupValue); + return true; + case 21: + hatchEdge.y2 = toReal(groupValue); + hatchEdge.defined = true; + return true; + } + } + + // Arc edge: + if (hatchEdge.type==2) { + switch(groupCode) { + case 10: + hatchEdge.cx = toReal(groupValue); + return true; + case 20: + hatchEdge.cy = toReal(groupValue); + return true; + case 40: + hatchEdge.radius = toReal(groupValue); + return true; + case 50: + hatchEdge.angle1 = toReal(groupValue)/360.0*2*M_PI; + return true; + case 51: + hatchEdge.angle2 = toReal(groupValue)/360.0*2*M_PI; + return true; + case 73: + hatchEdge.ccw = (bool)toInt(groupValue); + hatchEdge.defined = true; + return true; + } + } + + // Ellipse arc edge: + if (hatchEdge.type==3) { + switch (groupCode) { + case 10: + hatchEdge.cx = toReal(groupValue); + return true; + case 20: + hatchEdge.cy = toReal(groupValue); + return true; + case 11: + hatchEdge.mx = toReal(groupValue); + return true; + case 21: + hatchEdge.my = toReal(groupValue); + return true; + case 40: + hatchEdge.ratio = toReal(groupValue); + return true; + case 50: + hatchEdge.angle1 = toReal(groupValue)/360.0*2*M_PI; + return true; + case 51: + hatchEdge.angle2 = toReal(groupValue)/360.0*2*M_PI; + return true; + case 73: + hatchEdge.ccw = (bool)toInt(groupValue); + hatchEdge.defined = true; + return true; + } + } + + // Spline edge: + if (hatchEdge.type==4) { + switch (groupCode) { + case 94: + hatchEdge.degree = toInt(groupValue); + return true; + case 73: + hatchEdge.rational = toBool(groupValue); + return true; + case 74: + hatchEdge.periodic = toBool(groupValue); + return true; + case 95: + hatchEdge.nKnots = toInt(groupValue); + return true; + case 96: + hatchEdge.nControl = toInt(groupValue); + return true; + case 97: + hatchEdge.nFit = toInt(groupValue); + return true; + case 40: + if (hatchEdge.knots.size() < hatchEdge.nKnots) { + hatchEdge.knots.push_back(toReal(groupValue)); + } + return true; + case 10: + if (hatchEdge.controlPoints.size() < hatchEdge.nControl) { + std::vector v; + v.push_back(toReal(groupValue)); + hatchEdge.controlPoints.push_back(v); + } + return true; + case 20: + if (!hatchEdge.controlPoints.empty() && hatchEdge.controlPoints.back().size()==1) { + hatchEdge.controlPoints.back().push_back(toReal(groupValue)); + } + hatchEdge.defined = true; + return true; + case 42: + if (hatchEdge.weights.size() < hatchEdge.nControl) { + hatchEdge.weights.push_back(toReal(groupValue)); + } + return true; + case 11: + if (hatchEdge.fitPoints.size() < hatchEdge.nFit) { + std::vector v; + v.push_back(toReal(groupValue)); + hatchEdge.fitPoints.push_back(v); + } + return true; + case 21: + if (!hatchEdge.fitPoints.empty() && hatchEdge.fitPoints.back().size()==1) { + hatchEdge.fitPoints.back().push_back(toReal(groupValue)); + } + hatchEdge.defined = true; + return true; + case 12: + hatchEdge.startTangentX = toReal(groupValue); + return true; + case 22: + hatchEdge.startTangentY = toReal(groupValue); + return true; + case 13: + hatchEdge.endTangentX = toReal(groupValue); + return true; + case 23: + hatchEdge.endTangentY = toReal(groupValue); + return true; + } + } + } + + return false; +} + + +/** + * Adds an image entity that was read from the file via the creation interface. + */ +void DL_Dxf::addImage(DL_CreationInterface* creationInterface) { + DL_ImageData id(// pass ref insead of name we don't have yet + getStringValue(340, ""), + // ins point: + getRealValue(10, 0.0), + getRealValue(20, 0.0), + getRealValue(30, 0.0), + // u vector: + getRealValue(11, 1.0), + getRealValue(21, 0.0), + getRealValue(31, 0.0), + // v vector: + getRealValue(12, 0.0), + getRealValue(22, 1.0), + getRealValue(32, 0.0), + // image size (pixel): + getIntValue(13, 1), + getIntValue(23, 1), + // brightness, contrast, fade + getIntValue(281, 50), + getIntValue(282, 50), + getIntValue(283, 0)); + + creationInterface->addImage(id); + creationInterface->endEntity(); + currentObjectType = DL_UNKNOWN; +} + + + +/** + * Adds an image definition that was read from the file via the creation interface. + */ +void DL_Dxf::addImageDef(DL_CreationInterface* creationInterface) { + DL_ImageDefData id(// handle + getStringValue(5, ""), + getStringValue(1, "")); + + creationInterface->linkImage(id); + creationInterface->endEntity(); + currentObjectType = DL_UNKNOWN; +} + + + +/** + * Ends some special entities like hatches or old style polylines. + */ +void DL_Dxf::endEntity(DL_CreationInterface* creationInterface) { + creationInterface->endEntity(); +} + + +/** + * Ends a sequence and notifies the creation interface. + */ +void DL_Dxf::endSequence(DL_CreationInterface* creationInterface) { + creationInterface->endSequence(); +} + + +/** + * Converts the given string into an int. + * ok is set to false if there was an error. + */ +//int DL_Dxf::stringToInt(const char* s, bool* ok) { +// if (ok!=NULL) { +// // check string: +// *ok = true; +// int i=0; +// bool dot = false; +// do { +// if (s[i]=='\0') { +// break; +// } else if (s[i]=='.') { +// if (dot==true) { +// //std::cerr << "two dots\n"; +// *ok = false; +// } else { +// dot = true; +// } +// } else if (s[i]<'0' || s[i]>'9') { +// //std::cerr << "NaN: '" << s[i] << "'\n"; +// *ok = false; +// } +// i++; +// } while(s[i]!='\0' && *ok==true); +// } + +// return atoi(s); +//} + + +/** + * @brief Opens the given file for writing and returns a pointer + * to the dxf writer. This pointer needs to be passed on to other + * writing functions. + * + * @param file Full path of the file to open. + * + * @return Pointer to an ascii dxf writer object. + */ +DL_WriterA* DL_Dxf::out(const char* file, DL_Codes::version version) { + char* f = new char[strlen(file)+1]; + strcpy(f, file); + this->version = version; + + DL_WriterA* dw = new DL_WriterA(f, version); + if (dw->openFailed()) { + delete dw; + delete[] f; + return NULL; + } else { + delete[] f; + return dw; + } +} + + + +/** + * @brief Writes a DXF header to the file currently opened + * by the given DXF writer object. + */ +void DL_Dxf::writeHeader(DL_WriterA& dw) { + dw.comment("dxflib " DL_VERSION); + dw.sectionHeader(); + + dw.dxfString(9, "$ACADVER"); + switch (version) { + case DL_Codes::AC1009: + dw.dxfString(1, "AC1009"); + break; + case DL_Codes::AC1012: + dw.dxfString(1, "AC1012"); + break; + case DL_Codes::AC1014: + dw.dxfString(1, "AC1014"); + break; + case DL_Codes::AC1015: + dw.dxfString(1, "AC1015"); + break; + case DL_Codes::AC1009_MIN: + // minimalistic DXF version is unidentified in file: + break; + } + + // Newer version require that (otherwise a*cad crashes..) + if (version==DL_VERSION_2000) { + dw.dxfString(9, "$HANDSEED"); + dw.dxfHex(5, 0xFFFF); + } + + // commented out: more variables can be added after that by caller: + //dw.sectionEnd(); +} + + + + +/** + * Writes a point entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writePoint(DL_WriterA& dw, + const DL_PointData& data, + const DL_Attributes& attrib) { + dw.entity("POINT"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbPoint"); + } + dw.coord(DL_POINT_COORD_CODE, data.x, data.y, data.z); +} + + + +/** + * Writes a line entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeLine(DL_WriterA& dw, + const DL_LineData& data, + const DL_Attributes& attrib) { + dw.entity("LINE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbLine"); + } + dw.coord(DL_LINE_START_CODE, data.x1, data.y1, data.z1); + dw.coord(DL_LINE_END_CODE, data.x2, data.y2, data.z2); +} + + + +/** + * Writes an x line entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeXLine(DL_WriterA& dw, + const DL_XLineData& data, + const DL_Attributes& attrib) { + dw.entity("XLINE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbLine"); + } + dw.coord(DL_LINE_START_CODE, data.bx, data.by, data.bz); + dw.coord(DL_LINE_END_CODE, data.dx, data.dy, data.dz); +} + + + +/** + * Writes a ray entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeRay(DL_WriterA& dw, + const DL_RayData& data, + const DL_Attributes& attrib) { + dw.entity("RAY"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbLine"); + } + dw.coord(DL_LINE_START_CODE, data.bx, data.by, data.bz); + dw.coord(DL_LINE_END_CODE, data.dx, data.dy, data.dz); +} + + + +/** + * Writes a polyline entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + * @see writeVertex + */ +void DL_Dxf::writePolyline(DL_WriterA& dw, + const DL_PolylineData& data, + const DL_Attributes& attrib) { + if (version==DL_VERSION_2000) { + dw.entity("LWPOLYLINE"); + dw.dxfString(100, "AcDbEntity"); + dw.entityAttributes(attrib); + dw.dxfString(100, "AcDbPolyline"); + dw.dxfInt(90, (int)data.number); + dw.dxfInt(70, data.flags); + } else { + dw.entity("POLYLINE"); + dw.entityAttributes(attrib); + polylineLayer = attrib.getLayer(); + dw.dxfInt(66, 1); + dw.dxfInt(70, data.flags); + dw.coord(DL_VERTEX_COORD_CODE, 0.0, 0.0, 0.0); + } +} + + + +/** + * Writes a single vertex of a polyline to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeVertex(DL_WriterA& dw, + const DL_VertexData& data) { + + + if (version==DL_VERSION_2000) { + dw.dxfReal(10, data.x); + dw.dxfReal(20, data.y); + dw.dxfReal(30, data.z); + if (fabs(data.bulge)>1.0e-10) { + dw.dxfReal(42, data.bulge); + } + } else { + dw.entity("VERTEX"); + //dw.entityAttributes(attrib); + dw.dxfString(8, polylineLayer); + dw.coord(DL_VERTEX_COORD_CODE, data.x, data.y, data.z); + if (fabs(data.bulge)>1.0e-10) { + dw.dxfReal(42, data.bulge); + } + } +} + + + +/** + * Writes the polyline end. Only needed for DXF R12. + */ +void DL_Dxf::writePolylineEnd(DL_WriterA& dw) { + if (version==DL_VERSION_2000) { + } else { + dw.entity("SEQEND"); + } +} + + +/** + * Writes a spline entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + * @see writeControlPoint + */ +void DL_Dxf::writeSpline(DL_WriterA& dw, + const DL_SplineData& data, + const DL_Attributes& attrib) { + + dw.entity("SPLINE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSpline"); + } + dw.dxfInt(70, data.flags); + dw.dxfInt(71, data.degree); + dw.dxfInt(72, data.nKnots); // number of knots + dw.dxfInt(73, data.nControl); // number of control points + dw.dxfInt(74, data.nFit); // number of fit points +} + + + +/** + * Writes a single control point of a spline to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeControlPoint(DL_WriterA& dw, + const DL_ControlPointData& data) { + + dw.dxfReal(10, data.x); + dw.dxfReal(20, data.y); + dw.dxfReal(30, data.z); +} + + + +/** + * Writes a single fit point of a spline to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeFitPoint(DL_WriterA& dw, + const DL_FitPointData& data) { + + dw.dxfReal(11, data.x); + dw.dxfReal(21, data.y); + dw.dxfReal(31, data.z); +} + + + +/** + * Writes a single knot of a spline to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeKnot(DL_WriterA& dw, + const DL_KnotData& data) { + + dw.dxfReal(40, data.k); +} + + + +/** + * Writes a circle entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeCircle(DL_WriterA& dw, + const DL_CircleData& data, + const DL_Attributes& attrib) { + dw.entity("CIRCLE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbCircle"); + } + dw.coord(10, data.cx, data.cy, data.cz); + dw.dxfReal(40, data.radius); +} + + + +/** + * Writes an arc entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeArc(DL_WriterA& dw, + const DL_ArcData& data, + const DL_Attributes& attrib) { + dw.entity("ARC"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbCircle"); + } + dw.coord(10, data.cx, data.cy, data.cz); + dw.dxfReal(40, data.radius); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbArc"); + } + dw.dxfReal(50, data.angle1); + dw.dxfReal(51, data.angle2); +} + + + +/** + * Writes an ellipse entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeEllipse(DL_WriterA& dw, + const DL_EllipseData& data, + const DL_Attributes& attrib) { + + if (version>DL_VERSION_R12) { + dw.entity("ELLIPSE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEllipse"); + } + dw.coord(10, data.cx, data.cy, data.cz); + dw.coord(11, data.mx, data.my, data.mz); + dw.dxfReal(40, data.ratio); + dw.dxfReal(41, data.angle1); + dw.dxfReal(42, data.angle2); + } +} + + + +/** + * Writes a solid entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeSolid(DL_WriterA& dw, + const DL_SolidData& data, + const DL_Attributes& attrib) { + dw.entity("SOLID"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbTrace"); + } + dw.coord(10, data.x[0], data.y[0], data.z[0]); + dw.coord(11, data.x[1], data.y[1], data.z[1]); + dw.coord(12, data.x[2], data.y[2], data.z[2]); + dw.coord(13, data.x[3], data.y[3], data.z[3]); + dw.dxfReal(39, data.thickness); +} + +/** + * Writes a trace entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeTrace(DL_WriterA& dw, + const DL_TraceData& data, + const DL_Attributes& attrib) { + dw.entity("TRACE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbTrace"); + } + dw.coord(10, data.x[0], data.y[0], data.z[0]); + dw.coord(11, data.x[1], data.y[1], data.z[1]); + dw.coord(12, data.x[2], data.y[2], data.z[2]); + dw.coord(13, data.x[3], data.y[3], data.z[3]); + dw.dxfReal(39, data.thickness); +} + + + +/** + * Writes a 3d face entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::write3dFace(DL_WriterA& dw, + const DL_3dFaceData& data, + const DL_Attributes& attrib) { + dw.entity("3DFACE"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbFace"); + } + dw.coord(10, data.x[0], data.y[0], data.z[0]); + dw.coord(11, data.x[1], data.y[1], data.z[1]); + dw.coord(12, data.x[2], data.y[2], data.z[2]); + dw.coord(13, data.x[3], data.y[3], data.z[3]); +} + + + +/** + * Writes an insert to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeInsert(DL_WriterA& dw, + const DL_InsertData& data, + const DL_Attributes& attrib) { + + if (data.name.empty()) { + std::cerr << "DL_Dxf::writeInsert: " + << "Block name must not be empty\n"; + return; + } + + dw.entity("INSERT"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + if (data.cols!=1 || data.rows!=1) { + dw.dxfString(100, "AcDbMInsertBlock"); + } + else { + dw.dxfString(100, "AcDbBlockReference"); + } + } + dw.dxfString(2, data.name); + dw.dxfReal(10, data.ipx); + dw.dxfReal(20, data.ipy); + dw.dxfReal(30, data.ipz); + if (data.sx!=1.0 || data.sy!=1.0) { + dw.dxfReal(41, data.sx); + dw.dxfReal(42, data.sy); + dw.dxfReal(43, 1.0); + } + if (data.angle!=0.0) { + dw.dxfReal(50, data.angle); + } + if (data.cols!=1 || data.rows!=1) { + dw.dxfInt(70, data.cols); + dw.dxfInt(71, data.rows); + } + if (data.colSp!=0.0 || data.rowSp!=0.0) { + dw.dxfReal(44, data.colSp); + dw.dxfReal(45, data.rowSp); + } +} + + + +/** + * Writes a multi text entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeMText(DL_WriterA& dw, + const DL_MTextData& data, + const DL_Attributes& attrib) { + + dw.entity("MTEXT"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbMText"); + } + dw.dxfReal(10, data.ipx); + dw.dxfReal(20, data.ipy); + dw.dxfReal(30, data.ipz); + dw.dxfReal(40, data.height); + dw.dxfReal(41, data.width); + + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.drawingDirection); + + // Creare text chunks of 250 characters each: + int length = data.text.length(); + char chunk[251]; + int i; + for (i=250; iDL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbAlignedDimension"); + } + + dw.dxfReal(13, edata.epx1); + dw.dxfReal(23, edata.epy1); + dw.dxfReal(33, 0.0); + + dw.dxfReal(14, edata.epx2); + dw.dxfReal(24, edata.epy2); + dw.dxfReal(34, 0.0); + + writeDimStyleOverrides(dw, data); +} + + + +/** + * Writes a linear dimension entity to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific linear dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimLinear(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimLinearData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + dw.dxfInt(70, data.type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbAlignedDimension"); + } + + dw.dxfReal(13, edata.dpx1); + dw.dxfReal(23, edata.dpy1); + dw.dxfReal(33, 0.0); + + dw.dxfReal(14, edata.dpx2); + dw.dxfReal(24, edata.dpy2); + dw.dxfReal(34, 0.0); + + dw.dxfReal(50, edata.angle/(2.0*M_PI)*360.0); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbRotatedDimension"); + } + + writeDimStyleOverrides(dw, data); +} + + + +/** + * Writes a radial dimension entity to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific radial dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimRadial(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimRadialData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + dw.dxfInt(70, data.type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbRadialDimension"); + } + + dw.dxfReal(15, edata.dpx); + dw.dxfReal(25, edata.dpy); + dw.dxfReal(35, 0.0); + + dw.dxfReal(40, edata.leader); + + writeDimStyleOverrides(dw, data); +} + + + +/** + * Writes a diametric dimension entity to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific diametric dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimDiametric(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimDiametricData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + dw.dxfInt(70, data.type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDiametricDimension"); + } + + dw.dxfReal(15, edata.dpx); + dw.dxfReal(25, edata.dpy); + dw.dxfReal(35, 0.0); + + dw.dxfReal(40, edata.leader); + + writeDimStyleOverrides(dw, data); +} + + + +/** + * Writes an angular dimension entity to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific angular dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimAngular(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimAngularData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + dw.dxfInt(70, data.type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDb2LineAngularDimension"); + } + + dw.dxfReal(13, edata.dpx1); + dw.dxfReal(23, edata.dpy1); + dw.dxfReal(33, 0.0); + + dw.dxfReal(14, edata.dpx2); + dw.dxfReal(24, edata.dpy2); + dw.dxfReal(34, 0.0); + + dw.dxfReal(15, edata.dpx3); + dw.dxfReal(25, edata.dpy3); + dw.dxfReal(35, 0.0); + + dw.dxfReal(16, edata.dpx4); + dw.dxfReal(26, edata.dpy4); + dw.dxfReal(36, 0.0); +} + + + +/** + * Writes an angular dimension entity (3 points version) to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific angular dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimAngular3P(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimAngular3PData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + dw.dxfInt(70, data.type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfReal(42, data.angle); + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDb3PointAngularDimension"); + } + + dw.dxfReal(13, edata.dpx1); + dw.dxfReal(23, edata.dpy1); + dw.dxfReal(33, 0.0); + + dw.dxfReal(14, edata.dpx2); + dw.dxfReal(24, edata.dpy2); + dw.dxfReal(34, 0.0); + + dw.dxfReal(15, edata.dpx3); + dw.dxfReal(25, edata.dpy3); + dw.dxfReal(35, 0.0); +} + + + + +/** + * Writes an ordinate dimension entity to the file. + * + * @param dw DXF writer + * @param data Generic dimension data for from the file + * @param data Specific ordinate dimension data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeDimOrdinate(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimOrdinateData& edata, + const DL_Attributes& attrib) { + + dw.entity("DIMENSION"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimension"); + } + + dw.dxfReal(10, data.dpx); + dw.dxfReal(20, data.dpy); + dw.dxfReal(30, data.dpz); + + dw.dxfReal(11, data.mpx); + dw.dxfReal(21, data.mpy); + dw.dxfReal(31, 0.0); + + int type = data.type; + if (edata.xtype) { + type|=0x40; + } + + dw.dxfInt(70, type); + if (version>DL_VERSION_R12) { + dw.dxfInt(71, data.attachmentPoint); + dw.dxfInt(72, data.lineSpacingStyle); // opt + dw.dxfReal(41, data.lineSpacingFactor); // opt + } + + dw.dxfString(1, data.text); // opt + //dw.dxfString(3, data.style); + dw.dxfString(3, "Standard"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbOrdinateDimension"); + } + + dw.dxfReal(13, edata.dpx1); + dw.dxfReal(23, edata.dpy1); + dw.dxfReal(33, 0.0); + + dw.dxfReal(14, edata.dpx2); + dw.dxfReal(24, edata.dpy2); + dw.dxfReal(34, 0.0); +} + + + +/** + * Writes a leader entity to the file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + * @see writeVertex + */ +void DL_Dxf::writeLeader(DL_WriterA& dw, + const DL_LeaderData& data, + const DL_Attributes& attrib) { + if (version>DL_VERSION_R12) { + dw.entity("LEADER"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbLeader"); + } + dw.dxfString(3, "Standard"); + dw.dxfInt(71, data.arrowHeadFlag); + dw.dxfInt(72, data.leaderPathType); + dw.dxfInt(73, data.leaderCreationFlag); + dw.dxfInt(74, data.hooklineDirectionFlag); + dw.dxfInt(75, data.hooklineFlag); + dw.dxfReal(40, data.textAnnotationHeight); + dw.dxfReal(41, data.textAnnotationWidth); + dw.dxfInt(76, data.number); + } +} + + + +/** + * Writes a single vertex of a leader to the file. + * + * @param dw DXF writer + * @param data Entity data + */ +void DL_Dxf::writeLeaderVertex(DL_WriterA& dw, + const DL_LeaderVertexData& data) { + if (version>DL_VERSION_R12) { + dw.dxfReal(10, data.x); + dw.dxfReal(20, data.y); + } +} + + + +/** + * Writes the beginning of a hatch entity to the file. + * This must be followed by one or more writeHatchLoop() + * calls and a writeHatch2() call. + * + * @param dw DXF writer + * @param data Entity data. + * @param attrib Attributes + */ +void DL_Dxf::writeHatch1(DL_WriterA& dw, + const DL_HatchData& data, + const DL_Attributes& attrib) { + + dw.entity("HATCH"); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbHatch"); + } + dw.dxfReal(10, 0.0); // elevation + dw.dxfReal(20, 0.0); + dw.dxfReal(30, 0.0); + dw.dxfReal(210, 0.0); // extrusion dir. + dw.dxfReal(220, 0.0); + dw.dxfReal(230, 1.0); + if (data.solid==false) { + dw.dxfString(2, data.pattern); + } else { + dw.dxfString(2, "SOLID"); + } + dw.dxfInt(70, (int)data.solid); + dw.dxfInt(71, 0); // non-associative + dw.dxfInt(91, data.numLoops); +} + + + +/** + * Writes the end of a hatch entity to the file. + * + * @param dw DXF writer + * @param data Entity data. + * @param attrib Attributes + */ +void DL_Dxf::writeHatch2(DL_WriterA& dw, + const DL_HatchData& data, + const DL_Attributes& /*attrib*/) { + + dw.dxfInt(75, 0); // odd parity + dw.dxfInt(76, 1); // pattern type + if (data.solid==false) { + dw.dxfReal(52, data.angle); + dw.dxfReal(41, data.scale); + dw.dxfInt(77, 0); // not double + //dw.dxfInt(78, 0); + dw.dxfInt(78, 1); + dw.dxfReal(53, 45.0); + dw.dxfReal(43, 0.0); + dw.dxfReal(44, 0.0); + dw.dxfReal(45, -0.0883883476483184); + dw.dxfReal(46, 0.0883883476483185); + dw.dxfInt(79, 0); + } + dw.dxfInt(98, 0); + + if (version==DL_VERSION_2000) { + dw.dxfString(1001, "ACAD"); + dw.dxfReal(1010, data.originX); + dw.dxfReal(1020, data.originY); + dw.dxfInt(1030, 0.0); + } +} + + + +/** + * Writes the beginning of a hatch loop to the file. This + * must happen after writing the beginning of a hatch entity. + * + * @param dw DXF writer + * @param data Entity data. + * @param attrib Attributes + */ +void DL_Dxf::writeHatchLoop1(DL_WriterA& dw, + const DL_HatchLoopData& data) { + + dw.dxfInt(92, 1); + dw.dxfInt(93, data.numEdges); + //dw.dxfInt(97, 0); +} + + + +/** + * Writes the end of a hatch loop to the file. + * + * @param dw DXF writer + * @param data Entity data. + * @param attrib Attributes + */ +void DL_Dxf::writeHatchLoop2(DL_WriterA& dw, + const DL_HatchLoopData& /*data*/) { + + dw.dxfInt(97, 0); +} + + +/** + * Writes the beginning of a hatch entity to the file. + * + * @param dw DXF writer + * @param data Entity data. + * @param attrib Attributes + */ +void DL_Dxf::writeHatchEdge(DL_WriterA& dw, + const DL_HatchEdgeData& data) { + + if (data.type<1 || data.type>4) { + printf("WARNING: unsupported hatch edge type: %d", data.type); + } + + dw.dxfInt(72, data.type); + + switch (data.type) { + // line: + case 1: + dw.dxfReal(10, data.x1); + dw.dxfReal(20, data.y1); + dw.dxfReal(11, data.x2); + dw.dxfReal(21, data.y2); + break; + + // arc: + case 2: + dw.dxfReal(10, data.cx); + dw.dxfReal(20, data.cy); + dw.dxfReal(40, data.radius); + dw.dxfReal(50, data.angle1/(2*M_PI)*360.0); + dw.dxfReal(51, data.angle2/(2*M_PI)*360.0); + dw.dxfInt(73, (int)(data.ccw)); + break; + + // ellipse arc: + case 3: + dw.dxfReal(10, data.cx); + dw.dxfReal(20, data.cy); + dw.dxfReal(11, data.mx); + dw.dxfReal(21, data.my); + dw.dxfReal(40, data.ratio); + dw.dxfReal(50, data.angle1/(2*M_PI)*360.0); + dw.dxfReal(51, data.angle2/(2*M_PI)*360.0); + dw.dxfInt(73, (int)(data.ccw)); + break; + + // spline: + case 4: + dw.dxfInt(94, data.degree); + dw.dxfBool(73, data.rational); + dw.dxfBool(74, data.periodic); + dw.dxfInt(95, data.nKnots); + dw.dxfInt(96, data.nControl); + for (unsigned int i=0; i0) { + dw.dxfInt(97, data.nFit); + for (unsigned int i=0; i1.0e-4 || fabs(data.startTangentY)>1.0e-4) { + dw.dxfReal(12, data.startTangentX); + dw.dxfReal(22, data.startTangentY); + } + if (fabs(data.endTangentX)>1.0e-4 || fabs(data.endTangentY)>1.0e-4) { + dw.dxfReal(13, data.endTangentX); + dw.dxfReal(23, data.endTangentY); + } + break; + + default: + break; + } +} + + + +/** + * Writes an image entity. + * + * @return IMAGEDEF handle. Needed for the IMAGEDEF counterpart. + */ +int DL_Dxf::writeImage(DL_WriterA& dw, + const DL_ImageData& data, + const DL_Attributes& attrib) { + + /*if (data.file.empty()) { + std::cerr << "DL_Dxf::writeImage: " + << "Image file must not be empty\n"; + return; +}*/ + + dw.entity("IMAGE"); + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbEntity"); + } + dw.entityAttributes(attrib); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbRasterImage"); + dw.dxfInt(90, 0); + } + // insertion point + dw.dxfReal(10, data.ipx); + dw.dxfReal(20, data.ipy); + dw.dxfReal(30, data.ipz); + + // vector along bottom side (1 pixel long) + dw.dxfReal(11, data.ux); + dw.dxfReal(21, data.uy); + dw.dxfReal(31, data.uz); + + // vector along left side (1 pixel long) + dw.dxfReal(12, data.vx); + dw.dxfReal(22, data.vy); + dw.dxfReal(32, data.vz); + + // image size in pixel + dw.dxfReal(13, data.width); + dw.dxfReal(23, data.height); + + // handle of IMAGEDEF object + int handle = dw.incHandle(); + dw.dxfHex(340, handle); + + // flags + dw.dxfInt(70, 15); + + // clipping: + dw.dxfInt(280, 0); + + // brightness, contrast, fade + dw.dxfInt(281, data.brightness); + dw.dxfInt(282, data.contrast); + dw.dxfInt(283, data.fade); + + return handle; +} + + + +/** + * Writes an image definiition entity. + */ +void DL_Dxf::writeImageDef(DL_WriterA& dw, + int handle, + const DL_ImageData& data) { + + /*if (data.file.empty()) { + std::cerr << "DL_Dxf::writeImage: " + << "Image file must not be empty\n"; + return; +}*/ + + dw.dxfString(0, "IMAGEDEF"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, handle); + } + + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbRasterImageDef"); + dw.dxfInt(90, 0); + } + // file name: + dw.dxfString(1, data.ref); + + // image size in pixel + dw.dxfReal(10, data.width); + dw.dxfReal(20, data.height); + + dw.dxfReal(11, 1.0); + dw.dxfReal(21, 1.0); + + // loaded: + dw.dxfInt(280, 1); + // units: + dw.dxfInt(281, 0); +} + + +/** + * Writes a layer to the file. Layers are stored in the + * tables section of a DXF file. + * + * @param dw DXF writer + * @param data Entity data from the file + * @param attrib Attributes + */ +void DL_Dxf::writeLayer(DL_WriterA& dw, + const DL_LayerData& data, + const DL_Attributes& attrib) { + + if (data.name.empty()) { + std::cerr << "DL_Dxf::writeLayer: " + << "Layer name must not be empty\n"; + return; + } + + int color = attrib.getColor(); + if (color>=256) { + std::cerr << "Layer color cannot be " << color << ". Changed to 7.\n"; + color = 7; + } + if (data.off) { + // negative color value means layer is off: + color = -color; + } + + if (data.name == "0") { + dw.tableLayerEntry(0x10); + } else { + dw.tableLayerEntry(); + } + + dw.dxfString(2, data.name); + dw.dxfInt(70, data.flags); + dw.dxfInt(62, color); + if (version>=DL_VERSION_2000 && attrib.getColor24()!=-1) { + dw.dxfInt(420, attrib.getColor24()); + } + + dw.dxfString(6, (attrib.getLinetype().length()==0 ? + std::string("CONTINUOUS") : attrib.getLinetype())); + + if (version>=DL_VERSION_2000) { + // layer defpoints cannot be plotted + std::string lstr = data.name; + std::transform(lstr.begin(), lstr.end(), lstr.begin(), tolower); + if (lstr=="defpoints") { + dw.dxfInt(290, 0); + } + } + if (version>=DL_VERSION_2000 && attrib.getWidth()!=-1) { + dw.dxfInt(370, attrib.getWidth()); + } + if (version>=DL_VERSION_2000) { + dw.dxfHex(390, 0xF); + } +} + + + +/** + * Writes a line type to the file. Line types are stored in the + * tables section of a DXF file. + */ +void DL_Dxf::writeLinetype(DL_WriterA& dw, + const DL_LinetypeData& data) { + + std::string nameUpper = data.name; + std::transform(nameUpper.begin(), nameUpper.end(), nameUpper.begin(), ::toupper); + + if (data.name.empty()) { + std::cerr << "DL_Dxf::writeLinetype: " + << "Line type name must not be empty\n"; + return; + } + + // ignore BYLAYER, BYBLOCK for R12 + if (version=DL_VERSION_R13) { + dw.dxfInt(74, 0); + } + } + } +} + + + +/** + * Writes the APPID section to the DXF file. + * + * @param name Application name + */ +void DL_Dxf::writeAppid(DL_WriterA& dw, const std::string& name) { + if (name.empty()) { + std::cerr << "DL_Dxf::writeAppid: " + << "Application name must not be empty\n"; + return; + } + + std::string n = name; + std::transform(n.begin(), n.end(), n.begin(), ::toupper); + + if (n=="ACAD") { + dw.tableAppidEntry(0x12); + } else { + dw.tableAppidEntry(); + } + dw.dxfString(2, name); + dw.dxfInt(70, 0); +} + + + +/** + * Writes a block's definition (no entities) to the DXF file. + */ +void DL_Dxf::writeBlock(DL_WriterA& dw, const DL_BlockData& data) { + if (data.name.empty()) { + std::cerr << "DL_Dxf::writeBlock: " + << "Block name must not be empty\n"; + return; + } + + std::string n = data.name; + std::transform(n.begin(), n.end(), n.begin(), ::toupper); + + if (n=="*PAPER_SPACE") { + dw.sectionBlockEntry(0x1C); + } else if (n=="*MODEL_SPACE") { + dw.sectionBlockEntry(0x20); + } else if (n=="*PAPER_SPACE0") { + dw.sectionBlockEntry(0x24); + } else { + dw.sectionBlockEntry(); + } + dw.dxfString(2, data.name); + dw.dxfInt(70, 0); + dw.coord(10, data.bpx, data.bpy, data.bpz); + dw.dxfString(3, data.name); + dw.dxfString(1, ""); +} + + + +/** + * Writes a block end. + * + * @param name Block name + */ +void DL_Dxf::writeEndBlock(DL_WriterA& dw, const std::string& name) { + std::string n = name; + std::transform(n.begin(), n.end(), n.begin(), ::toupper); + + if (n=="*PAPER_SPACE") { + dw.sectionBlockEntryEnd(0x1D); + } else if (n=="*MODEL_SPACE") { + dw.sectionBlockEntryEnd(0x21); + } else if (n=="*PAPER_SPACE0") { + dw.sectionBlockEntryEnd(0x25); + } else { + dw.sectionBlockEntryEnd(); + } +} + + + +/** + * Writes a viewport section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked VPORT section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeVPort(DL_WriterA& dw) { + dw.dxfString(0, "TABLE"); + dw.dxfString(2, "VPORT"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 0x8); + } + //dw.dxfHex(330, 0); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTable"); + } + dw.dxfInt(70, 1); + dw.dxfString(0, "VPORT"); + //dw.dxfHex(5, 0x2F); + if (version==DL_VERSION_2000) { + dw.handle(); + } + //dw.dxfHex(330, 8); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbViewportTableRecord"); + } + dw.dxfString( 2, "*Active"); + dw.dxfInt( 70, 0); + dw.dxfReal( 10, 0.0); + dw.dxfReal( 20, 0.0); + dw.dxfReal( 11, 1.0); + dw.dxfReal( 21, 1.0); + dw.dxfReal( 12, 286.3055555555555); + dw.dxfReal( 22, 148.5); + dw.dxfReal( 13, 0.0); + dw.dxfReal( 23, 0.0); + dw.dxfReal( 14, 10.0); + dw.dxfReal( 24, 10.0); + dw.dxfReal( 15, 10.0); + dw.dxfReal( 25, 10.0); + dw.dxfReal( 16, 0.0); + dw.dxfReal( 26, 0.0); + dw.dxfReal( 36, 1.0); + dw.dxfReal( 17, 0.0); + dw.dxfReal( 27, 0.0); + dw.dxfReal( 37, 0.0); + dw.dxfReal( 40, 297.0); + dw.dxfReal( 41, 1.92798353909465); + dw.dxfReal( 42, 50.0); + dw.dxfReal( 43, 0.0); + dw.dxfReal( 44, 0.0); + dw.dxfReal( 50, 0.0); + dw.dxfReal( 51, 0.0); + dw.dxfInt( 71, 0); + dw.dxfInt( 72, 100); + dw.dxfInt( 73, 1); + dw.dxfInt( 74, 3); + dw.dxfInt( 75, 1); + dw.dxfInt( 76, 1); + dw.dxfInt( 77, 0); + dw.dxfInt( 78, 0); + + if (version==DL_VERSION_2000) { + dw.dxfInt(281, 0); + dw.dxfInt( 65, 1); + dw.dxfReal(110, 0.0); + dw.dxfReal(120, 0.0); + dw.dxfReal(130, 0.0); + dw.dxfReal(111, 1.0); + dw.dxfReal(121, 0.0); + dw.dxfReal(131, 0.0); + dw.dxfReal(112, 0.0); + dw.dxfReal(122, 1.0); + dw.dxfReal(132, 0.0); + dw.dxfInt( 79, 0); + dw.dxfReal(146, 0.0); + } + dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a style section. This section is needed in DL_VERSION_R13. + */ +void DL_Dxf::writeStyle(DL_WriterA& dw, const DL_StyleData& style) { +// dw.dxfString( 0, "TABLE"); +// dw.dxfString( 2, "STYLE"); +// if (version==DL_VERSION_2000) { +// dw.dxfHex(5, 3); +// } + //dw.dxfHex(330, 0); +// if (version==DL_VERSION_2000) { +// dw.dxfString(100, "AcDbSymbolTable"); +// } +// dw.dxfInt( 70, 1); + dw.dxfString( 0, "STYLE"); + if (version==DL_VERSION_2000) { + if (style.name=="Standard") { + //dw.dxfHex(5, 0x11); + styleHandleStd = dw.handle(); + } + else { + dw.handle(); + } + } + //dw.dxfHex(330, 3); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbTextStyleTableRecord"); + } + dw.dxfString( 2, style.name); + dw.dxfInt( 70, style.flags); + dw.dxfReal( 40, style.fixedTextHeight); + dw.dxfReal( 41, style.widthFactor); + dw.dxfReal( 50, style.obliqueAngle); + dw.dxfInt( 71, style.textGenerationFlags); + dw.dxfReal( 42, style.lastHeightUsed); + if (version==DL_VERSION_2000) { + dw.dxfString( 3, ""); + dw.dxfString( 4, ""); + dw.dxfString(1001, "ACAD"); + //dw.dxfString(1000, style.name); + dw.dxfString(1000, style.primaryFontFile); + int xFlags = 0; + if (style.bold) { + xFlags = xFlags|0x2000000; + } + if (style.italic) { + xFlags = xFlags|0x1000000; + } + dw.dxfInt(1071, xFlags); + } + else { + dw.dxfString( 3, style.primaryFontFile); + dw.dxfString( 4, style.bigFontFile); + } + //dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a view section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked VIEW section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeView(DL_WriterA& dw) { + dw.dxfString( 0, "TABLE"); + dw.dxfString( 2, "VIEW"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 6); + } + //dw.dxfHex(330, 0); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTable"); + } + dw.dxfInt( 70, 0); + dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a ucs section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked UCS section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeUcs(DL_WriterA& dw) { + dw.dxfString( 0, "TABLE"); + dw.dxfString( 2, "UCS"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 7); + } + //dw.dxfHex(330, 0); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTable"); + } + dw.dxfInt( 70, 0); + dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a dimstyle section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked DIMSTYLE section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeDimStyle(DL_WriterA& dw, + double dimasz, double dimexe, double dimexo, + double dimgap, double dimtxt) { + + dw.dxfString( 0, "TABLE"); + dw.dxfString( 2, "DIMSTYLE"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 0xA); + dw.dxfString(100, "AcDbSymbolTable"); + } + dw.dxfInt( 70, 1); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbDimStyleTable"); + dw.dxfInt( 71, 0); + } + + + dw.dxfString( 0, "DIMSTYLE"); + if (version==DL_VERSION_2000) { + dw.dxfHex(105, 0x27); + } + //dw.handle(105); + //dw.dxfHex(330, 0xA); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbDimStyleTableRecord"); + } + dw.dxfString( 2, "Standard"); + if (version==DL_VERSION_R12) { + dw.dxfString( 3, ""); + dw.dxfString( 4, ""); + dw.dxfString( 5, ""); + dw.dxfString( 6, ""); + dw.dxfString( 7, ""); + dw.dxfReal( 40, 1.0); + } + + dw.dxfReal( 41, dimasz); + dw.dxfReal( 42, dimexo); + dw.dxfReal( 43, 3.75); + dw.dxfReal( 44, dimexe); + if (version==DL_VERSION_R12) { + dw.dxfReal( 45, 0.0); + dw.dxfReal( 46, 0.0); + dw.dxfReal( 47, 0.0); + dw.dxfReal( 48, 0.0); + } + dw.dxfInt( 70, 0); + if (version==DL_VERSION_R12) { + dw.dxfInt( 71, 0); + dw.dxfInt( 72, 0); + } + dw.dxfInt( 73, 0); + dw.dxfInt( 74, 0); + if (version==DL_VERSION_R12) { + dw.dxfInt( 75, 0); + dw.dxfInt( 76, 0); + } + dw.dxfInt( 77, 1); + dw.dxfInt( 78, 8); + dw.dxfReal(140, dimtxt); + dw.dxfReal(141, 2.5); + if (version==DL_VERSION_R12) { + dw.dxfReal(142, 0.0); + } + dw.dxfReal(143, 0.03937007874016); + if (version==DL_VERSION_R12) { + dw.dxfReal(144, 1.0); + dw.dxfReal(145, 0.0); + dw.dxfReal(146, 1.0); + } + dw.dxfReal(147, dimgap); + if (version==DL_VERSION_R12) { + dw.dxfInt(170, 0); + } + dw.dxfInt(171, 3); + dw.dxfInt(172, 1); + if (version==DL_VERSION_R12) { + dw.dxfInt(173, 0); + dw.dxfInt(174, 0); + dw.dxfInt(175, 0); + dw.dxfInt(176, 0); + dw.dxfInt(177, 0); + dw.dxfInt(178, 0); + } + if (version==DL_VERSION_2000) { + dw.dxfInt(271, 2); + dw.dxfInt(272, 2); + dw.dxfInt(274, 3); + dw.dxfInt(278, 44); + dw.dxfInt(283, 0); + dw.dxfInt(284, 8); + dw.dxfHex(340, styleHandleStd); + //dw.dxfHex(340, 0x11); + } + // * / + dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a blockrecord section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked BLOCKRECORD section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeBlockRecord(DL_WriterA& dw) { + dw.dxfString( 0, "TABLE"); + dw.dxfString( 2, "BLOCK_RECORD"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 1); + } + //dw.dxfHex(330, 0); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTable"); + } + dw.dxfInt( 70, 1); + + dw.dxfString( 0, "BLOCK_RECORD"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 0x1F); + } + //int msh = dw.handle(); + //dw.setModelSpaceHandle(msh); + //dw.dxfHex(330, 1); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbBlockTableRecord"); + } + dw.dxfString( 2, "*Model_Space"); + dw.dxfHex(340, 0x22); + + dw.dxfString( 0, "BLOCK_RECORD"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 0x1B); + } + //int psh = dw.handle(); + //dw.setPaperSpaceHandle(psh); + //dw.dxfHex(330, 1); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbBlockTableRecord"); + } + dw.dxfString( 2, "*Paper_Space"); + dw.dxfHex(340, 0x1E); + + dw.dxfString( 0, "BLOCK_RECORD"); + if (version==DL_VERSION_2000) { + dw.dxfHex(5, 0x23); + } + //int ps0h = dw.handle(); + //dw.setPaperSpace0Handle(ps0h); + //dw.dxfHex(330, 1); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbBlockTableRecord"); + } + dw.dxfString( 2, "*Paper_Space0"); + dw.dxfHex(340, 0x26); + + //dw.dxfString( 0, "ENDTAB"); +} + + + +/** + * Writes a single block record with the given name. + */ +void DL_Dxf::writeBlockRecord(DL_WriterA& dw, const std::string& name) { + dw.dxfString( 0, "BLOCK_RECORD"); + if (version==DL_VERSION_2000) { + dw.handle(); + } + //dw->dxfHex(330, 1); + if (version==DL_VERSION_2000) { + dw.dxfString(100, "AcDbSymbolTableRecord"); + dw.dxfString(100, "AcDbBlockTableRecord"); + } + dw.dxfString( 2, name); + dw.dxfHex(340, 0); +} + + + +/** + * Writes a objects section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked OBJECTS section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeObjects(DL_WriterA& dw, const std::string& appDictionaryName) { + dw.dxfString( 0, "SECTION"); + dw.dxfString( 2, "OBJECTS"); + + + dw.dxfString( 0, "DICTIONARY"); + dw.dxfHex(5, 0xC); + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(280, 0); + dw.dxfInt(281, 1); + dw.dxfString( 3, "ACAD_GROUP"); + dw.dxfHex(350, 0xD); + dw.dxfString( 3, "ACAD_LAYOUT"); + dw.dxfHex(350, 0x1A); + dw.dxfString( 3, "ACAD_MLINESTYLE"); + dw.dxfHex(350, 0x17); + dw.dxfString( 3, "ACAD_PLOTSETTINGS"); + dw.dxfHex(350, 0x19); + dw.dxfString( 3, "ACAD_PLOTSTYLENAME"); + dw.dxfHex(350, 0xE); + dw.dxfString( 3, "AcDbVariableDictionary"); + int acDbVariableDictionaryHandle = dw.handle(350); + //int acDbVariableDictionaryHandle = dw.getNextHandle(); + //dw.dxfHex(350, acDbVariableDictionaryHandle); + //dw.incHandle(); + + if (appDictionaryName.length()!=0) { + dw.dxfString( 3, appDictionaryName); + appDictionaryHandle = dw.handle(350); + //appDictionaryHandle = dw.getNextHandle(); + //dw.dxfHex(350, appDictionaryHandle); + //dw.incHandle(); + } + + dw.dxfString( 0, "DICTIONARY"); + dw.dxfHex(5, 0xD); + //dw.handle(); // D + //dw.dxfHex(330, 0xC); + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(280, 0); + dw.dxfInt(281, 1); + + + dw.dxfString( 0, "ACDBDICTIONARYWDFLT"); + dw.dxfHex(5, 0xE); + //dicId4 = dw.handle(); // E + //dw.dxfHex(330, 0xC); // C + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(281, 1); + dw.dxfString( 3, "Normal"); + dw.dxfHex(350, 0xF); + //dw.dxfHex(350, dw.getNextHandle()+5); // F + dw.dxfString(100, "AcDbDictionaryWithDefault"); + dw.dxfHex(340, 0xF); + //dw.dxfHex(340, dw.getNextHandle()+5); // F + + + dw.dxfString( 0, "ACDBPLACEHOLDER"); + dw.dxfHex(5, 0xF); + //dw.handle(); // F + //dw.dxfHex(330, dicId4); // E + + + dw.dxfString( 0, "DICTIONARY"); + //dicId3 = dw.handle(); // 17 + dw.dxfHex(5, 0x17); + //dw.dxfHex(330, 0xC); // C + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(280, 0); + dw.dxfInt(281, 1); + dw.dxfString( 3, "Standard"); + dw.dxfHex(350, 0x18); + //dw.dxfHex(350, dw.getNextHandle()+5); // 18 + + + dw.dxfString( 0, "MLINESTYLE"); + dw.dxfHex(5, 0x18); + //dw.handle(); // 18 + //dw.dxfHex(330, dicId3); // 17 + dw.dxfString(100, "AcDbMlineStyle"); + dw.dxfString( 2, "STANDARD"); + dw.dxfInt( 70, 0); + dw.dxfString( 3, ""); + dw.dxfInt( 62, 256); + dw.dxfReal( 51, 90.0); + dw.dxfReal( 52, 90.0); + dw.dxfInt( 71, 2); + dw.dxfReal( 49, 0.5); + dw.dxfInt( 62, 256); + dw.dxfString( 6, "BYLAYER"); + dw.dxfReal( 49, -0.5); + dw.dxfInt( 62, 256); + dw.dxfString( 6, "BYLAYER"); + + + dw.dxfString( 0, "DICTIONARY"); + dw.dxfHex(5, 0x19); + //dw.handle(); // 17 + //dw.dxfHex(330, 0xC); // C + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(280, 0); + dw.dxfInt(281, 1); + + + dw.dxfString( 0, "DICTIONARY"); + //dicId2 = dw.handle(); // 1A + dw.dxfHex(5, 0x1A); + //dw.dxfHex(330, 0xC); + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(281, 1); + dw.dxfString( 3, "Layout1"); + dw.dxfHex(350, 0x1E); + //dw.dxfHex(350, dw.getNextHandle()+2); // 1E + dw.dxfString( 3, "Layout2"); + dw.dxfHex(350, 0x26); + //dw.dxfHex(350, dw.getNextHandle()+4); // 26 + dw.dxfString( 3, "Model"); + dw.dxfHex(350, 0x22); + //dw.dxfHex(350, dw.getNextHandle()+5); // 22 + + + dw.dxfString( 0, "LAYOUT"); + dw.dxfHex(5, 0x1E); + //dw.handle(); // 1E + //dw.dxfHex(330, dicId2); // 1A + dw.dxfString(100, "AcDbPlotSettings"); + dw.dxfString( 1, ""); + dw.dxfString( 2, "none_device"); + dw.dxfString( 4, ""); + dw.dxfString( 6, ""); + dw.dxfReal( 40, 0.0); + dw.dxfReal( 41, 0.0); + dw.dxfReal( 42, 0.0); + dw.dxfReal( 43, 0.0); + dw.dxfReal( 44, 0.0); + dw.dxfReal( 45, 0.0); + dw.dxfReal( 46, 0.0); + dw.dxfReal( 47, 0.0); + dw.dxfReal( 48, 0.0); + dw.dxfReal( 49, 0.0); + dw.dxfReal(140, 0.0); + dw.dxfReal(141, 0.0); + dw.dxfReal(142, 1.0); + dw.dxfReal(143, 1.0); + dw.dxfInt( 70, 688); + dw.dxfInt( 72, 0); + dw.dxfInt( 73, 0); + dw.dxfInt( 74, 5); + dw.dxfString( 7, ""); + dw.dxfInt( 75, 16); + dw.dxfReal(147, 1.0); + dw.dxfReal(148, 0.0); + dw.dxfReal(149, 0.0); + dw.dxfString(100, "AcDbLayout"); + dw.dxfString( 1, "Layout1"); + dw.dxfInt( 70, 1); + dw.dxfInt( 71, 1); + dw.dxfReal( 10, 0.0); + dw.dxfReal( 20, 0.0); + dw.dxfReal( 11, 420.0); + dw.dxfReal( 21, 297.0); + dw.dxfReal( 12, 0.0); + dw.dxfReal( 22, 0.0); + dw.dxfReal( 32, 0.0); + dw.dxfReal( 14, 1.000000000000000E+20); + dw.dxfReal( 24, 1.000000000000000E+20); + dw.dxfReal( 34, 1.000000000000000E+20); + dw.dxfReal( 15, -1.000000000000000E+20); + dw.dxfReal( 25, -1.000000000000000E+20); + dw.dxfReal( 35, -1.000000000000000E+20); + dw.dxfReal(146, 0.0); + dw.dxfReal( 13, 0.0); + dw.dxfReal( 23, 0.0); + dw.dxfReal( 33, 0.0); + dw.dxfReal( 16, 1.0); + dw.dxfReal( 26, 0.0); + dw.dxfReal( 36, 0.0); + dw.dxfReal( 17, 0.0); + dw.dxfReal( 27, 1.0); + dw.dxfReal( 37, 0.0); + dw.dxfInt( 76, 0); + //dw.dxfHex(330, dw.getPaperSpaceHandle()); // 1B + dw.dxfHex(330, 0x1B); + + + dw.dxfString( 0, "LAYOUT"); + dw.dxfHex(5, 0x22); + //dw.handle(); // 22 + //dw.dxfHex(330, dicId2); // 1A + dw.dxfString(100, "AcDbPlotSettings"); + dw.dxfString( 1, ""); + dw.dxfString( 2, "none_device"); + dw.dxfString( 4, ""); + dw.dxfString( 6, ""); + dw.dxfReal( 40, 0.0); + dw.dxfReal( 41, 0.0); + dw.dxfReal( 42, 0.0); + dw.dxfReal( 43, 0.0); + dw.dxfReal( 44, 0.0); + dw.dxfReal( 45, 0.0); + dw.dxfReal( 46, 0.0); + dw.dxfReal( 47, 0.0); + dw.dxfReal( 48, 0.0); + dw.dxfReal( 49, 0.0); + dw.dxfReal(140, 0.0); + dw.dxfReal(141, 0.0); + dw.dxfReal(142, 1.0); + dw.dxfReal(143, 1.0); + dw.dxfInt( 70, 1712); + dw.dxfInt( 72, 0); + dw.dxfInt( 73, 0); + dw.dxfInt( 74, 0); + dw.dxfString( 7, ""); + dw.dxfInt( 75, 0); + dw.dxfReal(147, 1.0); + dw.dxfReal(148, 0.0); + dw.dxfReal(149, 0.0); + dw.dxfString(100, "AcDbLayout"); + dw.dxfString( 1, "Model"); + dw.dxfInt( 70, 1); + dw.dxfInt( 71, 0); + dw.dxfReal( 10, 0.0); + dw.dxfReal( 20, 0.0); + dw.dxfReal( 11, 12.0); + dw.dxfReal( 21, 9.0); + dw.dxfReal( 12, 0.0); + dw.dxfReal( 22, 0.0); + dw.dxfReal( 32, 0.0); + dw.dxfReal( 14, 0.0); + dw.dxfReal( 24, 0.0); + dw.dxfReal( 34, 0.0); + dw.dxfReal( 15, 0.0); + dw.dxfReal( 25, 0.0); + dw.dxfReal( 35, 0.0); + dw.dxfReal(146, 0.0); + dw.dxfReal( 13, 0.0); + dw.dxfReal( 23, 0.0); + dw.dxfReal( 33, 0.0); + dw.dxfReal( 16, 1.0); + dw.dxfReal( 26, 0.0); + dw.dxfReal( 36, 0.0); + dw.dxfReal( 17, 0.0); + dw.dxfReal( 27, 1.0); + dw.dxfReal( 37, 0.0); + dw.dxfInt( 76, 0); + //dw.dxfHex(330, dw.getModelSpaceHandle()); // 1F + dw.dxfHex(330, 0x1F); + + + dw.dxfString( 0, "LAYOUT"); + //dw.handle(); // 26 + dw.dxfHex(5, 0x26); + //dw.dxfHex(330, dicId2); // 1A + dw.dxfString(100, "AcDbPlotSettings"); + dw.dxfString( 1, ""); + dw.dxfString( 2, "none_device"); + dw.dxfString( 4, ""); + dw.dxfString( 6, ""); + dw.dxfReal( 40, 0.0); + dw.dxfReal( 41, 0.0); + dw.dxfReal( 42, 0.0); + dw.dxfReal( 43, 0.0); + dw.dxfReal( 44, 0.0); + dw.dxfReal( 45, 0.0); + dw.dxfReal( 46, 0.0); + dw.dxfReal( 47, 0.0); + dw.dxfReal( 48, 0.0); + dw.dxfReal( 49, 0.0); + dw.dxfReal(140, 0.0); + dw.dxfReal(141, 0.0); + dw.dxfReal(142, 1.0); + dw.dxfReal(143, 1.0); + dw.dxfInt( 70, 688); + dw.dxfInt( 72, 0); + dw.dxfInt( 73, 0); + dw.dxfInt( 74, 5); + dw.dxfString( 7, ""); + dw.dxfInt( 75, 16); + dw.dxfReal(147, 1.0); + dw.dxfReal(148, 0.0); + dw.dxfReal(149, 0.0); + dw.dxfString(100, "AcDbLayout"); + dw.dxfString( 1, "Layout2"); + dw.dxfInt( 70, 1); + dw.dxfInt( 71, 2); + dw.dxfReal( 10, 0.0); + dw.dxfReal( 20, 0.0); + dw.dxfReal( 11, 12.0); + dw.dxfReal( 21, 9.0); + dw.dxfReal( 12, 0.0); + dw.dxfReal( 22, 0.0); + dw.dxfReal( 32, 0.0); + dw.dxfReal( 14, 0.0); + dw.dxfReal( 24, 0.0); + dw.dxfReal( 34, 0.0); + dw.dxfReal( 15, 0.0); + dw.dxfReal( 25, 0.0); + dw.dxfReal( 35, 0.0); + dw.dxfReal(146, 0.0); + dw.dxfReal( 13, 0.0); + dw.dxfReal( 23, 0.0); + dw.dxfReal( 33, 0.0); + dw.dxfReal( 16, 1.0); + dw.dxfReal( 26, 0.0); + dw.dxfReal( 36, 0.0); + dw.dxfReal( 17, 0.0); + dw.dxfReal( 27, 1.0); + dw.dxfReal( 37, 0.0); + dw.dxfInt( 76, 0); + //dw.dxfHex(330, dw.getPaperSpace0Handle()); // 23 + dw.dxfHex(330, 0x23); + + dw.dxfString( 0, "DICTIONARY"); + //dw.dxfHex(5, 0x2C); + //dicId5 = + dw.dxfHex(5, acDbVariableDictionaryHandle); + //dw.handle(); // 2C + //dw.dxfHex(330, 0xC); // C + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(281, 1); + dw.dxfString( 3, "DIMASSOC"); + //dw.dxfHex(350, 0x2F); + dw.dxfHex(350, dw.getNextHandle()+1); // 2E + dw.dxfString( 3, "HIDETEXT"); + //dw.dxfHex(350, 0x2E); + dw.dxfHex(350, dw.getNextHandle()); // 2D + + + dw.dxfString( 0, "DICTIONARYVAR"); + //dw.dxfHex(5, 0x2E); + dw.handle(); // 2E + //dw.dxfHex(330, dicId5); // 2C + dw.dxfString(100, "DictionaryVariables"); + dw.dxfInt(280, 0); + dw.dxfInt( 1, 2); + + + dw.dxfString( 0, "DICTIONARYVAR"); + //dw.dxfHex(5, 0x2D); + dw.handle(); // 2D + //dw.dxfHex(330, dicId5); // 2C + dw.dxfString(100, "DictionaryVariables"); + dw.dxfInt(280, 0); + dw.dxfInt( 1, 1); +} + +void DL_Dxf::writeAppDictionary(DL_WriterA& dw) { + dw.dxfString( 0, "DICTIONARY"); + //dw.handle(); + dw.dxfHex(5, appDictionaryHandle); + dw.dxfString(100, "AcDbDictionary"); + dw.dxfInt(281, 1); +} + +int DL_Dxf::writeDictionaryEntry(DL_WriterA& dw, const std::string& name) { + dw.dxfString( 3, name); + int handle = dw.getNextHandle(); + dw.dxfHex(350, handle); + dw.incHandle(); + return handle; +} + +void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, int value) { + dw.dxfString( 0, "XRECORD"); + dw.dxfHex(5, handle); + dw.dxfHex(330, appDictionaryHandle); + dw.dxfString(100, "AcDbXrecord"); + dw.dxfInt(280, 1); + dw.dxfInt(90, value); +} + +void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, double value) { + dw.dxfString( 0, "XRECORD"); + dw.dxfHex(5, handle); + dw.dxfHex(330, appDictionaryHandle); + dw.dxfString(100, "AcDbXrecord"); + dw.dxfInt(280, 1); + dw.dxfReal(40, value); +} + +void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, bool value) { + dw.dxfString( 0, "XRECORD"); + dw.dxfHex(5, handle); + dw.dxfHex(330, appDictionaryHandle); + dw.dxfString(100, "AcDbXrecord"); + dw.dxfInt(280, 1); + dw.dxfBool(290, value); +} + +void DL_Dxf::writeXRecord(DL_WriterA& dw, int handle, const std::string& value) { + dw.dxfString( 0, "XRECORD"); + dw.dxfHex(5, handle); + dw.dxfHex(330, appDictionaryHandle); + dw.dxfString(100, "AcDbXrecord"); + dw.dxfInt(280, 1); + dw.dxfString(1000, value); +} + +/** + * Writes the end of the objects section. This section is needed in DL_VERSION_R13. + * Note that this method currently only writes a faked OBJECTS section + * to make the file readable by Aut*cad. + */ +void DL_Dxf::writeObjectsEnd(DL_WriterA& dw) { + dw.dxfString( 0, "ENDSEC"); +} + + + +/** + * Writes a comment to the DXF file. + */ +void DL_Dxf::writeComment(DL_WriterA& dw, const std::string& comment) { + dw.dxfString(999, comment); +} + + +/** + * Checks if the given variable is known by the given DXF version. + */ +bool DL_Dxf::checkVariable(const char* var, DL_Codes::version version) { + if (version>=DL_VERSION_2000) { + return true; + } else if (version==DL_VERSION_R12) { + // these are all the variables recognized by dxf r12: + if (!strcmp(var, "$ACADVER")) { + return true; + } + if (!strcmp(var, "$ACADVER")) { + return true; + } + if (!strcmp(var, "$ANGBASE")) { + return true; + } + if (!strcmp(var, "$ANGDIR")) { + return true; + } + if (!strcmp(var, "$ATTDIA")) { + return true; + } + if (!strcmp(var, "$ATTMODE")) { + return true; + } + if (!strcmp(var, "$ATTREQ")) { + return true; + } + if (!strcmp(var, "$AUNITS")) { + return true; + } + if (!strcmp(var, "$AUPREC")) { + return true; + } + if (!strcmp(var, "$AXISMODE")) { + return true; + } + if (!strcmp(var, "$AXISUNIT")) { + return true; + } + if (!strcmp(var, "$BLIPMODE")) { + return true; + } + if (!strcmp(var, "$CECOLOR")) { + return true; + } + if (!strcmp(var, "$CELTYPE")) { + return true; + } + if (!strcmp(var, "$CHAMFERA")) { + return true; + } + if (!strcmp(var, "$CHAMFERB")) { + return true; + } + if (!strcmp(var, "$CLAYER")) { + return true; + } + if (!strcmp(var, "$COORDS")) { + return true; + } + if (!strcmp(var, "$DIMALT")) { + return true; + } + if (!strcmp(var, "$DIMALTD")) { + return true; + } + if (!strcmp(var, "$DIMALTF")) { + return true; + } + if (!strcmp(var, "$DIMAPOST")) { + return true; + } + if (!strcmp(var, "$DIMASO")) { + return true; + } + if (!strcmp(var, "$DIMASZ")) { + return true; + } + if (!strcmp(var, "$DIMBLK")) { + return true; + } + if (!strcmp(var, "$DIMBLK1")) { + return true; + } + if (!strcmp(var, "$DIMBLK2")) { + return true; + } + if (!strcmp(var, "$DIMCEN")) { + return true; + } + if (!strcmp(var, "$DIMCLRD")) { + return true; + } + if (!strcmp(var, "$DIMCLRE")) { + return true; + } + if (!strcmp(var, "$DIMCLRT")) { + return true; + } + if (!strcmp(var, "$DIMDLE")) { + return true; + } + if (!strcmp(var, "$DIMDLI")) { + return true; + } + if (!strcmp(var, "$DIMEXE")) { + return true; + } + if (!strcmp(var, "$DIMEXO")) { + return true; + } + if (!strcmp(var, "$DIMGAP")) { + return true; + } + if (!strcmp(var, "$DIMLFAC")) { + return true; + } + if (!strcmp(var, "$DIMLIM")) { + return true; + } + if (!strcmp(var, "$DIMPOST")) { + return true; + } + if (!strcmp(var, "$DIMRND")) { + return true; + } + if (!strcmp(var, "$DIMSAH")) { + return true; + } + if (!strcmp(var, "$DIMSCALE")) { + return true; + } + if (!strcmp(var, "$DIMSE1")) { + return true; + } + if (!strcmp(var, "$DIMSE2")) { + return true; + } + if (!strcmp(var, "$DIMSHO")) { + return true; + } + if (!strcmp(var, "$DIMSOXD")) { + return true; + } + if (!strcmp(var, "$DIMSTYLE")) { + return true; + } + if (!strcmp(var, "$DIMTAD")) { + return true; + } + if (!strcmp(var, "$DIMTFAC")) { + return true; + } + if (!strcmp(var, "$DIMTIH")) { + return true; + } + if (!strcmp(var, "$DIMTIX")) { + return true; + } + if (!strcmp(var, "$DIMTM")) { + return true; + } + if (!strcmp(var, "$DIMTOFL")) { + return true; + } + if (!strcmp(var, "$DIMTOH")) { + return true; + } + if (!strcmp(var, "$DIMTOL")) { + return true; + } + if (!strcmp(var, "$DIMTP")) { + return true; + } + if (!strcmp(var, "$DIMTSZ")) { + return true; + } + if (!strcmp(var, "$DIMTVP")) { + return true; + } + if (!strcmp(var, "$DIMTXT")) { + return true; + } + if (!strcmp(var, "$DIMZIN")) { + return true; + } + if (!strcmp(var, "$DWGCODEPAGE")) { + return true; + } + if (!strcmp(var, "$DRAGMODE")) { + return true; + } + if (!strcmp(var, "$ELEVATION")) { + return true; + } + if (!strcmp(var, "$EXTMAX")) { + return true; + } + if (!strcmp(var, "$EXTMIN")) { + return true; + } + if (!strcmp(var, "$FILLETRAD")) { + return true; + } + if (!strcmp(var, "$FILLMODE")) { + return true; + } + if (!strcmp(var, "$HANDLING")) { + return true; + } + if (!strcmp(var, "$HANDSEED")) { + return true; + } + if (!strcmp(var, "$INSBASE")) { + return true; + } + if (!strcmp(var, "$LIMCHECK")) { + return true; + } + if (!strcmp(var, "$LIMMAX")) { + return true; + } + if (!strcmp(var, "$LIMMIN")) { + return true; + } + if (!strcmp(var, "$LTSCALE")) { + return true; + } + if (!strcmp(var, "$LUNITS")) { + return true; + } + if (!strcmp(var, "$LUPREC")) { + return true; + } + if (!strcmp(var, "$MAXACTVP")) { + return true; + } + if (!strcmp(var, "$MENU")) { + return true; + } + if (!strcmp(var, "$MIRRTEXT")) { + return true; + } + if (!strcmp(var, "$ORTHOMODE")) { + return true; + } + if (!strcmp(var, "$OSMODE")) { + return true; + } + if (!strcmp(var, "$PDMODE")) { + return true; + } + if (!strcmp(var, "$PDSIZE")) { + return true; + } + if (!strcmp(var, "$PELEVATION")) { + return true; + } + if (!strcmp(var, "$PEXTMAX")) { + return true; + } + if (!strcmp(var, "$PEXTMIN")) { + return true; + } + if (!strcmp(var, "$PLIMCHECK")) { + return true; + } + if (!strcmp(var, "$PLIMMAX")) { + return true; + } + if (!strcmp(var, "$PLIMMIN")) { + return true; + } + if (!strcmp(var, "$PLINEGEN")) { + return true; + } + if (!strcmp(var, "$PLINEWID")) { + return true; + } + if (!strcmp(var, "$PSLTSCALE")) { + return true; + } + if (!strcmp(var, "$PUCSNAME")) { + return true; + } + if (!strcmp(var, "$PUCSORG")) { + return true; + } + if (!strcmp(var, "$PUCSXDIR")) { + return true; + } + if (!strcmp(var, "$PUCSYDIR")) { + return true; + } + if (!strcmp(var, "$QTEXTMODE")) { + return true; + } + if (!strcmp(var, "$REGENMODE")) { + return true; + } + if (!strcmp(var, "$SHADEDGE")) { + return true; + } + if (!strcmp(var, "$SHADEDIF")) { + return true; + } + if (!strcmp(var, "$SKETCHINC")) { + return true; + } + if (!strcmp(var, "$SKPOLY")) { + return true; + } + if (!strcmp(var, "$SPLFRAME")) { + return true; + } + if (!strcmp(var, "$SPLINESEGS")) { + return true; + } + if (!strcmp(var, "$SPLINETYPE")) { + return true; + } + if (!strcmp(var, "$SURFTAB1")) { + return true; + } + if (!strcmp(var, "$SURFTAB2")) { + return true; + } + if (!strcmp(var, "$SURFTYPE")) { + return true; + } + if (!strcmp(var, "$SURFU")) { + return true; + } + if (!strcmp(var, "$SURFV")) { + return true; + } + if (!strcmp(var, "$TDCREATE")) { + return true; + } + if (!strcmp(var, "$TDINDWG")) { + return true; + } + if (!strcmp(var, "$TDUPDATE")) { + return true; + } + if (!strcmp(var, "$TDUSRTIMER")) { + return true; + } + if (!strcmp(var, "$TEXTSIZE")) { + return true; + } + if (!strcmp(var, "$TEXTSTYLE")) { + return true; + } + if (!strcmp(var, "$THICKNESS")) { + return true; + } + if (!strcmp(var, "$TILEMODE")) { + return true; + } + if (!strcmp(var, "$TRACEWID")) { + return true; + } + if (!strcmp(var, "$UCSNAME")) { + return true; + } + if (!strcmp(var, "$UCSORG")) { + return true; + } + if (!strcmp(var, "$UCSXDIR")) { + return true; + } + if (!strcmp(var, "$UCSYDIR")) { + return true; + } + if (!strcmp(var, "$UNITMODE")) { + return true; + } + if (!strcmp(var, "$USERI1")) { + return true; + } + if (!strcmp(var, "$USERR1")) { + return true; + } + if (!strcmp(var, "$USRTIMER")) { + return true; + } + if (!strcmp(var, "$VISRETAIN")) { + return true; + } + if (!strcmp(var, "$WORLDVIEW")) { + return true; + } + if (!strcmp(var, "$FASTZOOM")) { + return true; + } + if (!strcmp(var, "$GRIDMODE")) { + return true; + } + if (!strcmp(var, "$GRIDUNIT")) { + return true; + } + if (!strcmp(var, "$SNAPANG")) { + return true; + } + if (!strcmp(var, "$SNAPBASE")) { + return true; + } + if (!strcmp(var, "$SNAPISOPAIR")) { + return true; + } + if (!strcmp(var, "$SNAPMODE")) { + return true; + } + if (!strcmp(var, "$SNAPSTYLE")) { + return true; + } + if (!strcmp(var, "$SNAPUNIT")) { + return true; + } + if (!strcmp(var, "$VIEWCTR")) { + return true; + } + if (!strcmp(var, "$VIEWDIR")) { + return true; + } + if (!strcmp(var, "$VIEWSIZE")) { + return true; + } + return false; + } + + return false; +} + + + +/** + * @returns the library version as int (4 bytes, each byte one version number). + * e.g. if str = "2.0.2.0" getLibVersion returns 0x02000200 + */ +int DL_Dxf::getLibVersion(const std::string& str) { + int d[4]; + int idx = 0; + //char v[4][5]; + std::string v[4]; + int ret = 0; + + for (unsigned int i=0; i=2) { + d[3] = str.length(); + + v[0] = str.substr(0, d[0]); + v[1] = str.substr(d[0]+1, d[1]-d[0]-1); + v[2] = str.substr(d[1]+1, d[2]-d[1]-1); + if (idx>=3) { + v[3] = str.substr(d[2]+1, d[3]-d[2]-1); + } + else { + v[3] = "0"; + } + + ret = (atoi(v[0].c_str())<<(3*8)) + + (atoi(v[1].c_str())<<(2*8)) + + (atoi(v[2].c_str())<<(1*8)) + + (atoi(v[3].c_str())<<(0*8)); + + return ret; + } else { + std::cerr << "DL_Dxf::getLibVersion: invalid version number: " << str << "\n"; + return 0; + } +} + +/** + * Converts the given string into a double or returns the given + * default valud (def) if value is NULL or empty. + */ +//double DL_Dxf::toReal(const char* value, double def) { +// if (value!=NULL && value[0] != '\0') { +// printf("toReal: not empty: %s\n", value); +// printf("toReal: val: %f\n", atof(value)); +// printf("toReal: 0: %d\n", value[0]); +// printf("toReal: 1: %d\n", value[1]); +// printf("toReal: 2: %d\n", value[2]); +// double ret; +// if (strchr(value, ',') != NULL) { +// char* tmp = new char[strlen(value)+1]; +// strcpy(tmp, value); +// DL_WriterA::strReplace(tmp, ',', '.'); +// ret = atof(tmp); +// delete[] tmp; +// } +// else { +// ret = atof(value); +// } +// return ret; +// } else { +// return def; +// } +//} + + +/** + * Some test routines. + */ +void DL_Dxf::test() { + char* buf1; + char* buf2; + char* buf3; + char* buf4; + char* buf5; + char* buf6; + + buf1 = new char[10]; + buf2 = new char[10]; + buf3 = new char[10]; + buf4 = new char[10]; + buf5 = new char[10]; + buf6 = new char[10]; + + strcpy(buf1, " 10\n"); + strcpy(buf2, "10"); + strcpy(buf3, "10\n"); + strcpy(buf4, " 10 \n"); + strcpy(buf5, " 10 \r"); + strcpy(buf6, "\t10 \n"); + + std::cout << "1 buf1: '" << buf1 << "'\n"; + stripWhiteSpace(&buf1); + std::cout << "2 buf1: '" << buf1 << "'\n"; + //assert(!strcmp(buf1, "10")); + + std::cout << "1 buf2: '" << buf2 << "'\n"; + stripWhiteSpace(&buf2); + std::cout << "2 buf2: '" << buf2 << "'\n"; + + std::cout << "1 buf3: '" << buf3 << "'\n"; + stripWhiteSpace(&buf3); + std::cout << "2 buf3: '" << buf3 << "'\n"; + + std::cout << "1 buf4: '" << buf4 << "'\n"; + stripWhiteSpace(&buf4); + std::cout << "2 buf4: '" << buf4 << "'\n"; + + std::cout << "1 buf5: '" << buf5 << "'\n"; + stripWhiteSpace(&buf5); + std::cout << "2 buf5: '" << buf5 << "'\n"; + + std::cout << "1 buf6: '" << buf6 << "'\n"; + stripWhiteSpace(&buf6); + std::cout << "2 buf6: '" << buf6 << "'\n"; + +} + + diff --git a/datafile/dxf/dxflib/dl_dxf.h b/datafile/dxf/dxflib/dl_dxf.h new file mode 100644 index 0000000..54443c5 --- /dev/null +++ b/datafile/dxf/dxflib/dl_dxf.h @@ -0,0 +1,529 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_DXF_H +#define DL_DXF_H + +#include "dl_global.h" + +#include +#include +#include +#include +#include +#include + +#include "dl_attributes.h" +#include "dl_codes.h" +#include "dl_entities.h" +#include "dl_writer_ascii.h" + +#ifdef _WIN32 +#undef M_PI +#define M_PI 3.14159265358979323846 +//#pragma warning(disable : 4800) +#endif + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#ifndef DL_NANDOUBLE +#define DL_NANDOUBLE std::numeric_limits::quiet_NaN() +#endif + +class DL_CreationInterface; +class DL_WriterA; + + +#define DL_VERSION "3.17.0.0" + +#define DL_VERSION_MAJOR 3 +#define DL_VERSION_MINOR 17 +#define DL_VERSION_REV 0 +#define DL_VERSION_BUILD 0 + +#define DL_UNKNOWN 0 +#define DL_LAYER 10 +#define DL_BLOCK 11 +#define DL_ENDBLK 12 +#define DL_LINETYPE 13 +#define DL_STYLE 20 +#define DL_SETTING 50 +#define DL_ENTITY_POINT 100 +#define DL_ENTITY_LINE 101 +#define DL_ENTITY_POLYLINE 102 +#define DL_ENTITY_LWPOLYLINE 103 +#define DL_ENTITY_VERTEX 104 +#define DL_ENTITY_SPLINE 105 +#define DL_ENTITY_KNOT 106 +#define DL_ENTITY_CONTROLPOINT 107 +#define DL_ENTITY_ARC 108 +#define DL_ENTITY_CIRCLE 109 +#define DL_ENTITY_ELLIPSE 110 +#define DL_ENTITY_INSERT 111 +#define DL_ENTITY_TEXT 112 +#define DL_ENTITY_MTEXT 113 +#define DL_ENTITY_DIMENSION 114 +#define DL_ENTITY_LEADER 115 +#define DL_ENTITY_HATCH 116 +#define DL_ENTITY_ATTRIB 117 +#define DL_ENTITY_IMAGE 118 +#define DL_ENTITY_IMAGEDEF 119 +#define DL_ENTITY_TRACE 120 +#define DL_ENTITY_SOLID 121 +#define DL_ENTITY_3DFACE 122 +#define DL_ENTITY_XLINE 123 +#define DL_ENTITY_RAY 124 +#define DL_ENTITY_ARCALIGNEDTEXT 125 +#define DL_ENTITY_SEQEND 126 +#define DL_XRECORD 200 +#define DL_DICTIONARY 210 + + +/** + * Reading and writing of DXF files. + * + * This class can read in a DXF file and calls methods from the + * interface DL_EntityContainer to add the entities to the + * contianer provided by the user of the library. + * + * It can also be used to write DXF files to a certain extent. + * + * When saving entities, special values for colors and linetypes + * can be used: + * + * Special colors are 0 (=BYBLOCK) and 256 (=BYLAYER). + * Special linetypes are "BYLAYER" and "BYBLOCK". + * + * @author Andrew Mustun + */ +class DXFLIB_EXPORT DL_Dxf { +public: + DL_Dxf(); + ~DL_Dxf(); + + bool in(const std::string& file, + DL_CreationInterface* creationInterface); + bool readDxfGroups(FILE* fp, + DL_CreationInterface* creationInterface); + static bool getStrippedLine(std::string& s, unsigned int size, + FILE* stream, bool stripSpace = true); + + bool readDxfGroups(std::stringstream& stream, + DL_CreationInterface* creationInterface); + bool in(std::stringstream &stream, + DL_CreationInterface* creationInterface); + static bool getStrippedLine(std::string& s, unsigned int size, + std::stringstream& stream, bool stripSpace = true); + + static bool stripWhiteSpace(char** s, bool stripSpaces = true); + + bool processDXFGroup(DL_CreationInterface* creationInterface, + int groupCode, const std::string& groupValue); + void addSetting(DL_CreationInterface* creationInterface); + void addLayer(DL_CreationInterface* creationInterface); + void addLinetype(DL_CreationInterface *creationInterface); + void addBlock(DL_CreationInterface* creationInterface); + void endBlock(DL_CreationInterface* creationInterface); + void addTextStyle(DL_CreationInterface* creationInterface); + + void addPoint(DL_CreationInterface* creationInterface); + void addLine(DL_CreationInterface* creationInterface); + void addXLine(DL_CreationInterface* creationInterface); + void addRay(DL_CreationInterface* creationInterface); + + void addPolyline(DL_CreationInterface* creationInterface); + void addVertex(DL_CreationInterface* creationInterface); + + void addSpline(DL_CreationInterface* creationInterface); + + void addArc(DL_CreationInterface* creationInterface); + void addCircle(DL_CreationInterface* creationInterface); + void addEllipse(DL_CreationInterface* creationInterface); + void addInsert(DL_CreationInterface* creationInterface); + + void addTrace(DL_CreationInterface* creationInterface); + void add3dFace(DL_CreationInterface* creationInterface); + void addSolid(DL_CreationInterface* creationInterface); + + void addMText(DL_CreationInterface* creationInterface); + void addText(DL_CreationInterface* creationInterface); + void addArcAlignedText(DL_CreationInterface* creationInterface); + + void addAttribute(DL_CreationInterface* creationInterface); + + DL_DimensionData getDimData(); + void addDimLinear(DL_CreationInterface* creationInterface); + void addDimAligned(DL_CreationInterface* creationInterface); + void addDimRadial(DL_CreationInterface* creationInterface); + void addDimDiametric(DL_CreationInterface* creationInterface); + void addDimAngular(DL_CreationInterface* creationInterface); + void addDimAngular3P(DL_CreationInterface* creationInterface); + void addDimOrdinate(DL_CreationInterface* creationInterface); + + void addLeader(DL_CreationInterface* creationInterface); + + void addHatch(DL_CreationInterface* creationInterface); + void addHatchLoop(); + void addHatchEdge(); + bool handleHatchData(DL_CreationInterface* creationInterface); + + void addImage(DL_CreationInterface* creationInterface); + void addImageDef(DL_CreationInterface* creationInterface); + + void addComment(DL_CreationInterface* creationInterface, const std::string& comment); + + void addDictionary(DL_CreationInterface* creationInterface); + void addDictionaryEntry(DL_CreationInterface* creationInterface); + + bool handleXRecordData(DL_CreationInterface* creationInterface); + bool handleDictionaryData(DL_CreationInterface* creationInterface); + + bool handleXData(DL_CreationInterface *creationInterface); + bool handleMTextData(DL_CreationInterface* creationInterface); + bool handleLWPolylineData(DL_CreationInterface* creationInterface); + bool handleSplineData(DL_CreationInterface* creationInterface); + bool handleLeaderData(DL_CreationInterface* creationInterface); + bool handleLinetypeData(DL_CreationInterface* creationInterface); + + void endEntity(DL_CreationInterface* creationInterface); + + void endSequence(DL_CreationInterface* creationInterface); + + //int stringToInt(const char* s, bool* ok=NULL); + + DL_WriterA* out(const char* file, + DL_Codes::version version=DL_VERSION_2000); + + void writeHeader(DL_WriterA& dw); + + void writePoint(DL_WriterA& dw, + const DL_PointData& data, + const DL_Attributes& attrib); + void writeLine(DL_WriterA& dw, + const DL_LineData& data, + const DL_Attributes& attrib); + void writeXLine(DL_WriterA& dw, + const DL_XLineData& data, + const DL_Attributes& attrib); + void writeRay(DL_WriterA& dw, + const DL_RayData& data, + const DL_Attributes& attrib); + void writePolyline(DL_WriterA& dw, + const DL_PolylineData& data, + const DL_Attributes& attrib); + void writeVertex(DL_WriterA& dw, + const DL_VertexData& data); + void writePolylineEnd(DL_WriterA& dw); + void writeSpline(DL_WriterA& dw, + const DL_SplineData& data, + const DL_Attributes& attrib); + void writeControlPoint(DL_WriterA& dw, + const DL_ControlPointData& data); + void writeFitPoint(DL_WriterA& dw, + const DL_FitPointData& data); + void writeKnot(DL_WriterA& dw, + const DL_KnotData& data); + void writeCircle(DL_WriterA& dw, + const DL_CircleData& data, + const DL_Attributes& attrib); + void writeArc(DL_WriterA& dw, + const DL_ArcData& data, + const DL_Attributes& attrib); + void writeEllipse(DL_WriterA& dw, + const DL_EllipseData& data, + const DL_Attributes& attrib); + void writeSolid(DL_WriterA& dw, + const DL_SolidData& data, + const DL_Attributes& attrib); + void writeTrace(DL_WriterA& dw, + const DL_TraceData& data, + const DL_Attributes& attrib); + void write3dFace(DL_WriterA& dw, + const DL_3dFaceData& data, + const DL_Attributes& attrib); + void writeInsert(DL_WriterA& dw, + const DL_InsertData& data, + const DL_Attributes& attrib); + void writeMText(DL_WriterA& dw, + const DL_MTextData& data, + const DL_Attributes& attrib); + void writeText(DL_WriterA& dw, + const DL_TextData& data, + const DL_Attributes& attrib); + void writeAttribute(DL_WriterA& dw, + const DL_AttributeData& data, + const DL_Attributes& attrib); + void writeDimStyleOverrides(DL_WriterA& dw, + const DL_DimensionData& data); + void writeDimAligned(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimAlignedData& edata, + const DL_Attributes& attrib); + void writeDimLinear(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimLinearData& edata, + const DL_Attributes& attrib); + void writeDimRadial(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimRadialData& edata, + const DL_Attributes& attrib); + void writeDimDiametric(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimDiametricData& edata, + const DL_Attributes& attrib); + void writeDimAngular(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimAngularData& edata, + const DL_Attributes& attrib); + void writeDimAngular3P(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimAngular3PData& edata, + const DL_Attributes& attrib); + void writeDimOrdinate(DL_WriterA& dw, + const DL_DimensionData& data, + const DL_DimOrdinateData& edata, + const DL_Attributes& attrib); + void writeLeader(DL_WriterA& dw, + const DL_LeaderData& data, + const DL_Attributes& attrib); + void writeLeaderVertex(DL_WriterA& dw, + const DL_LeaderVertexData& data); + void writeHatch1(DL_WriterA& dw, + const DL_HatchData& data, + const DL_Attributes& attrib); + void writeHatch2(DL_WriterA& dw, + const DL_HatchData& data, + const DL_Attributes& attrib); + void writeHatchLoop1(DL_WriterA& dw, + const DL_HatchLoopData& data); + void writeHatchLoop2(DL_WriterA& dw, + const DL_HatchLoopData& data); + void writeHatchEdge(DL_WriterA& dw, + const DL_HatchEdgeData& data); + + int writeImage(DL_WriterA& dw, + const DL_ImageData& data, + const DL_Attributes& attrib); + + void writeImageDef(DL_WriterA& dw, int handle, + const DL_ImageData& data); + + void writeLayer(DL_WriterA& dw, + const DL_LayerData& data, + const DL_Attributes& attrib); + + void writeLinetype(DL_WriterA& dw, + const DL_LinetypeData& data); + + void writeAppid(DL_WriterA& dw, const std::string& name); + + void writeBlock(DL_WriterA& dw, + const DL_BlockData& data); + void writeEndBlock(DL_WriterA& dw, const std::string& name); + + void writeVPort(DL_WriterA& dw); + void writeStyle(DL_WriterA& dw, const DL_StyleData& style); + void writeView(DL_WriterA& dw); + void writeUcs(DL_WriterA& dw); + void writeDimStyle(DL_WriterA& dw, + double dimasz, double dimexe, double dimexo, + double dimgap, double dimtxt); + void writeBlockRecord(DL_WriterA& dw); + void writeBlockRecord(DL_WriterA& dw, const std::string& name); + void writeObjects(DL_WriterA& dw, const std::string& appDictionaryName = ""); + void writeAppDictionary(DL_WriterA& dw); + int writeDictionaryEntry(DL_WriterA& dw, const std::string& name); + void writeXRecord(DL_WriterA& dw, int handle, int value); + void writeXRecord(DL_WriterA& dw, int handle, double value); + void writeXRecord(DL_WriterA& dw, int handle, bool value); + void writeXRecord(DL_WriterA& dw, int handle, const std::string& value); + void writeObjectsEnd(DL_WriterA& dw); + + void writeComment(DL_WriterA& dw, const std::string& comment); + + /** + * Converts the given string into a double or returns the given + * default valud (def) if value is NULL or empty. + */ + //static double toReal(const char* value, double def=0.0); + + /** + * Converts the given string into an int or returns the given + * default valud (def) if value is NULL or empty. + */ +// static int toInt(const char* value, int def=0) { +// if (value!=NULL && value[0] != '\0') { +// return atoi(value); +// } + +// return def; +// } + + /** + * Converts the given string into a string or returns the given + * default valud (def) if value is NULL or empty. + */ +// static const char* toString(const char* value, const char* def="") { +// if (value!=NULL && value[0] != '\0') { +// return value; +// } else { +// return def; +// } +// } + + static bool checkVariable(const char* var, DL_Codes::version version); + + DL_Codes::version getVersion() { + return version; + } + + int getLibVersion(const std::string &str); + + static void test(); + + bool hasValue(int code) { + return values.count(code)==1; + } + + int getIntValue(int code, int def) { + if (!hasValue(code)) { + return def; + } + return toInt(values[code]); + } + + int toInt(const std::string& str) { + char* p; + return strtol(str.c_str(), &p, 10); + } + + int getInt16Value(int code, int def) { + if (!hasValue(code)) { + return def; + } + return toInt16(values[code]); + } + + int toInt16(const std::string& str) { + char* p; + return strtol(str.c_str(), &p, 16); + } + + bool toBool(const std::string& str) { + char* p; + return (bool)strtol(str.c_str(), &p, 10); + } + + std::string getStringValue(int code, const std::string& def) { + if (!hasValue(code)) { + return def; + } + return values[code]; + } + + double getRealValue(int code, double def) { + if (!hasValue(code)) { + return def; + } + return toReal(values[code]); + } + + double toReal(const std::string& str) { + double ret; + // make sure the real value uses '.' not ',': + std::string str2 = str; + std::replace(str2.begin(), str2.end(), ',', '.'); + // make sure c++ expects '.' not ',': + std::istringstream istr(str2); + //istr.imbue(std::locale("C")); + istr >> ret; + return ret; + } + +private: + DL_Codes::version version; + + std::string polylineLayer; + double* vertices; + int maxVertices; + int vertexIndex; + + double* knots; + int maxKnots; + int knotIndex; + + double* weights; + int weightIndex; + + double* controlPoints; + int maxControlPoints; + int controlPointIndex; + + double* fitPoints; + int maxFitPoints; + int fitPointIndex; + + double* leaderVertices; + int maxLeaderVertices; + int leaderVertexIndex; + + bool firstHatchLoop; + DL_HatchEdgeData hatchEdge; + std::vector > hatchEdges; + + std::string xRecordHandle; + bool xRecordValues; + + // Only the useful part of the group code + std::string groupCodeTmp; + // ...same as integer + unsigned int groupCode; + // Only the useful part of the group value + std::string groupValue; + // Current entity type + int currentObjectType; + // Value of the current setting + char settingValue[DL_DXF_MAXLINE+1]; + // Key of the current setting (e.g. "$ACADVER") + std::string settingKey; + // Stores the group codes + std::map values; + // First call of this method. We initialize all group values in + // the first call. + bool firstCall; + // Attributes of the current entity (layer, color, width, line type) + DL_Attributes attrib; + // library version. hex: 0x20003001 = 2.0.3.1 + int libVersion; + // app specific dictionary handle: + unsigned long appDictionaryHandle; + // handle of standard text style, referenced by dimstyle: + unsigned long styleHandleStd; +}; + +#endif + +// EOF diff --git a/datafile/dxf/dxflib/dl_entities.h b/datafile/dxf/dxflib/dl_entities.h new file mode 100644 index 0000000..7a4c7ad --- /dev/null +++ b/datafile/dxf/dxflib/dl_entities.h @@ -0,0 +1,1813 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_ENTITIES_H +#define DL_ENTITIES_H + +#include "dl_global.h" + +#include +#include + +/** + * Layer Data. + */ +struct DXFLIB_EXPORT DL_LayerData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_LayerData(const std::string& name, + int flags, bool off = false) : + name(name), flags(flags), off(off) { + } + + /** Layer name. */ + std::string name; + /** Layer flags. (1 = frozen, 2 = frozen by default, 4 = locked) */ + int flags; + /** Layer is off */ + bool off; +}; + + + +/** + * Block Data. + */ +struct DXFLIB_EXPORT DL_BlockData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_BlockData(const std::string& bName, + int bFlags, + double bbpx, double bbpy, double bbpz) { + name = bName; + flags = bFlags; + bpx = bbpx; + bpy = bbpy; + bpz = bbpz; + } + + /** Block name. */ + std::string name; + /** Block flags. (not used currently) */ + int flags; + /** X Coordinate of base point. */ + double bpx; + /** Y Coordinate of base point. */ + double bpy; + /** Z Coordinate of base point. */ + double bpz; +}; + + +/** + * Line Type Data. + */ +struct DXFLIB_EXPORT DL_LinetypeData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_LinetypeData( + const std::string& name, + const std::string& description, + int flags, + int numberOfDashes, + double patternLength, + double* pattern = NULL + ) + : name(name), + description(description), + flags(flags), + numberOfDashes(numberOfDashes), + patternLength(patternLength), + pattern(pattern) + {} + + /** Linetype name */ + std::string name; + /** Linetype description */ + std::string description; + /** Linetype flags */ + int flags; + /** Number of dashes */ + int numberOfDashes; + /** Pattern length */ + double patternLength; + /** Pattern */ + double* pattern; +}; + + + +/** + * Text style data. + */ +struct DXFLIB_EXPORT DL_StyleData { + /** + * Constructor + * Parameters: see member variables. + */ + DL_StyleData( + const std::string& name, + int flags, + double fixedTextHeight, + double widthFactor, + double obliqueAngle, + int textGenerationFlags, + double lastHeightUsed, + const std::string& primaryFontFile, + const std::string& bigFontFile + ) + : name(name), + flags(flags), + fixedTextHeight(fixedTextHeight), + widthFactor(widthFactor), + obliqueAngle(obliqueAngle), + textGenerationFlags(textGenerationFlags), + lastHeightUsed(lastHeightUsed), + primaryFontFile(primaryFontFile), + bigFontFile(bigFontFile), + bold(false), + italic(false) { + } + + bool operator==(const DL_StyleData& other) { + // ignore lastHeightUsed: + return (name==other.name && + flags==other.flags && + fixedTextHeight==other.fixedTextHeight && + widthFactor==other.widthFactor && + obliqueAngle==other.obliqueAngle && + textGenerationFlags==other.textGenerationFlags && + primaryFontFile==other.primaryFontFile && + bigFontFile==other.bigFontFile); + } + + /** Style name */ + std::string name; + /** Style flags */ + int flags; + /** Fixed text height or 0 for not fixed. */ + double fixedTextHeight; + /** Width factor */ + double widthFactor; + /** Oblique angle */ + double obliqueAngle; + /** Text generation flags */ + int textGenerationFlags; + /** Last height used */ + double lastHeightUsed; + /** Primary font file name */ + std::string primaryFontFile; + /** Big font file name */ + std::string bigFontFile; + + bool bold; + bool italic; +}; + +/** + * Point Data. + */ +struct DXFLIB_EXPORT DL_PointData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_PointData(double px=0.0, double py=0.0, double pz=0.0) { + x = px; + y = py; + z = pz; + } + + /*! X Coordinate of the point. */ + double x; + /*! Y Coordinate of the point. */ + double y; + /*! Z Coordinate of the point. */ + double z; +}; + + + +/** + * Line Data. + */ +struct DXFLIB_EXPORT DL_LineData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_LineData(double lx1, double ly1, double lz1, + double lx2, double ly2, double lz2) { + x1 = lx1; + y1 = ly1; + z1 = lz1; + + x2 = lx2; + y2 = ly2; + z2 = lz2; + } + + /*! X Start coordinate of the point. */ + double x1; + /*! Y Start coordinate of the point. */ + double y1; + /*! Z Start coordinate of the point. */ + double z1; + + /*! X End coordinate of the point. */ + double x2; + /*! Y End coordinate of the point. */ + double y2; + /*! Z End coordinate of the point. */ + double z2; +}; + +/** + * XLine Data. + */ +struct DXFLIB_EXPORT DL_XLineData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_XLineData(double bx, double by, double bz, + double dx, double dy, double dz) : + bx(bx), by(by), bz(bz), + dx(dx), dy(dy), dz(dz) { + } + + /*! X base point. */ + double bx; + /*! Y base point. */ + double by; + /*! Z base point. */ + double bz; + + /*! X direction vector. */ + double dx; + /*! Y direction vector. */ + double dy; + /*! Z direction vector. */ + double dz; +}; + +/** + * Ray Data. + */ +struct DXFLIB_EXPORT DL_RayData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_RayData(double bx, double by, double bz, + double dx, double dy, double dz) : + bx(bx), by(by), bz(bz), + dx(dx), dy(dy), dz(dz) { + } + + /*! X base point. */ + double bx; + /*! Y base point. */ + double by; + /*! Z base point. */ + double bz; + + /*! X direction vector. */ + double dx; + /*! Y direction vector. */ + double dy; + /*! Z direction vector. */ + double dz; +}; + + + +/** + * Arc Data. + */ +struct DXFLIB_EXPORT DL_ArcData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_ArcData(double acx, double acy, double acz, + double aRadius, + double aAngle1, double aAngle2) { + + cx = acx; + cy = acy; + cz = acz; + radius = aRadius; + angle1 = aAngle1; + angle2 = aAngle2; + } + + /*! X Coordinate of center point. */ + double cx; + /*! Y Coordinate of center point. */ + double cy; + /*! Z Coordinate of center point. */ + double cz; + + /*! Radius of arc. */ + double radius; + /*! Startangle of arc in degrees. */ + double angle1; + /*! Endangle of arc in degrees. */ + double angle2; +}; + + + +/** + * Circle Data. + */ +struct DXFLIB_EXPORT DL_CircleData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_CircleData(double acx, double acy, double acz, + double aRadius) { + + cx = acx; + cy = acy; + cz = acz; + radius = aRadius; + } + + /*! X Coordinate of center point. */ + double cx; + /*! Y Coordinate of center point. */ + double cy; + /*! Z Coordinate of center point. */ + double cz; + + /*! Radius of arc. */ + double radius; +}; + + + +/** + * Polyline Data. + */ +struct DXFLIB_EXPORT DL_PolylineData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_PolylineData(int pNumber, int pMVerteces, int pNVerteces, int pFlags, double pElevation = 0.0) { + number = pNumber; + m = pMVerteces; + n = pNVerteces; + elevation = pElevation; + flags = pFlags; + } + + /*! Number of vertices in this polyline. */ + unsigned int number; + + /*! Number of vertices in m direction if polyline is a polygon mesh. */ + unsigned int m; + + /*! Number of vertices in n direction if polyline is a polygon mesh. */ + unsigned int n; + + /*! elevation of the polyline. */ + double elevation; + + /*! Flags */ + int flags; +}; + + + +/** + * Vertex Data. + */ +struct DXFLIB_EXPORT DL_VertexData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_VertexData(double px=0.0, double py=0.0, double pz=0.0, + double pBulge=0.0) { + x = px; + y = py; + z = pz; + bulge = pBulge; + } + + /*! X Coordinate of the vertex. */ + double x; + /*! Y Coordinate of the vertex. */ + double y; + /*! Z Coordinate of the vertex. */ + double z; + /*! Bulge of vertex. + * (The tangent of 1/4 of the arc angle or 0 for lines) */ + double bulge; +}; + + +/** + * Trace Data / solid data / 3d face data. + */ +struct DXFLIB_EXPORT DL_TraceData { + DL_TraceData() { + thickness = 0.0; + for (int i=0; i<4; i++) { + x[i] = 0.0; + y[i] = 0.0; + z[i] = 0.0; + } + } + + /** + * Constructor. + * Parameters: see member variables. + */ + DL_TraceData(double sx1, double sy1, double sz1, + double sx2, double sy2, double sz2, + double sx3, double sy3, double sz3, + double sx4, double sy4, double sz4, + double sthickness=0.0) { + + thickness = sthickness; + + x[0] = sx1; + y[0] = sy1; + z[0] = sz1; + + x[1] = sx2; + y[1] = sy2; + z[1] = sz2; + + x[2] = sx3; + y[2] = sy3; + z[2] = sz3; + + x[3] = sx4; + y[3] = sy4; + z[3] = sz4; + } + + /*! Thickness */ + double thickness; + + /*! Points */ + double x[4]; + double y[4]; + double z[4]; +}; + + + + + +/** + * Solid Data. + */ +typedef DL_TraceData DL_SolidData; + + +/** + * 3dface Data. + */ +typedef DL_TraceData DL_3dFaceData; + + +/** + * Spline Data. + */ +struct DXFLIB_EXPORT DL_SplineData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_SplineData(int degree, + int nKnots, + int nControl, + int nFit, + int flags) : + degree(degree), + nKnots(nKnots), + nControl(nControl), + nFit(nFit), + flags(flags) { + } + + /*! Degree of the spline curve. */ + unsigned int degree; + + /*! Number of knots. */ + unsigned int nKnots; + + /*! Number of control points. */ + unsigned int nControl; + + /*! Number of fit points. */ + unsigned int nFit; + + /*! Flags */ + int flags; + + double tangentStartX; + double tangentStartY; + double tangentStartZ; + double tangentEndX; + double tangentEndY; + double tangentEndZ; +}; + + + +/** + * Spline knot data. + */ +struct DXFLIB_EXPORT DL_KnotData { + DL_KnotData() {} + /** + * Constructor. + * Parameters: see member variables. + */ + DL_KnotData(double pk) { + k = pk; + } + + /*! Knot value. */ + double k; +}; + + + +/** + * Spline control point data. + */ +struct DXFLIB_EXPORT DL_ControlPointData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_ControlPointData(double px, double py, double pz, double weight) { + x = px; + y = py; + z = pz; + w = weight; + } + + /*! X coordinate of the control point. */ + double x; + /*! Y coordinate of the control point. */ + double y; + /*! Z coordinate of the control point. */ + double z; + /*! Weight of control point. */ + double w; +}; + + + +/** + * Spline fit point data. + */ +struct DXFLIB_EXPORT DL_FitPointData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_FitPointData(double x, double y, double z) : x(x), y(y), z(z) {} + + /*! X coordinate of the fit point. */ + double x; + /*! Y coordinate of the fit point. */ + double y; + /*! Z coordinate of the fit point. */ + double z; +}; + + + +/** + * Ellipse Data. + */ +struct DXFLIB_EXPORT DL_EllipseData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_EllipseData(double cx, double cy, double cz, + double mx, double my, double mz, + double ratio, + double angle1, double angle2) + : cx(cx), + cy(cy), + cz(cz), + mx(mx), + my(my), + mz(mz), + ratio(ratio), + angle1(angle1), + angle2(angle2) { + } + + /*! X Coordinate of center point. */ + double cx; + /*! Y Coordinate of center point. */ + double cy; + /*! Z Coordinate of center point. */ + double cz; + + /*! X coordinate of the endpoint of the major axis. */ + double mx; + /*! Y coordinate of the endpoint of the major axis. */ + double my; + /*! Z coordinate of the endpoint of the major axis. */ + double mz; + + /*! Ratio of minor axis to major axis.. */ + double ratio; + /*! Startangle of ellipse in rad. */ + double angle1; + /*! Endangle of ellipse in rad. */ + double angle2; +}; + + + +/** + * Insert Data. + */ +struct DXFLIB_EXPORT DL_InsertData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_InsertData(const std::string& name, + double ipx, double ipy, double ipz, + double sx, double sy, double sz, + double angle, + int cols, int rows, + double colSp, double rowSp) : + name(name), + ipx(ipx), ipy(ipy), ipz(ipz), + sx(sx), sy(sy), sz(sz), + angle(angle), + cols(cols), rows(rows), + colSp(colSp), rowSp(rowSp) { + } + + /*! Name of the referred block. */ + std::string name; + /*! X Coordinate of insertion point. */ + double ipx; + /*! Y Coordinate of insertion point. */ + double ipy; + /*! Z Coordinate of insertion point. */ + double ipz; + /*! X Scale factor. */ + double sx; + /*! Y Scale factor. */ + double sy; + /*! Z Scale factor. */ + double sz; + /*! Rotation angle in degrees. */ + double angle; + /*! Number of colums if we insert an array of the block or 1. */ + int cols; + /*! Number of rows if we insert an array of the block or 1. */ + int rows; + /*! Values for the spacing between cols. */ + double colSp; + /*! Values for the spacing between rows. */ + double rowSp; +}; + + + +/** + * MText Data. + */ +struct DXFLIB_EXPORT DL_MTextData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_MTextData(double ipx, double ipy, double ipz, + double dirx, double diry, double dirz, + double height, double width, + int attachmentPoint, + int drawingDirection, + int lineSpacingStyle, + double lineSpacingFactor, + const std::string& text, + const std::string& style, + double angle) : + ipx(ipx), ipy(ipy), ipz(ipz), + dirx(dirx), diry(diry), dirz(dirz), + height(height), width(width), + attachmentPoint(attachmentPoint), + drawingDirection(drawingDirection), + lineSpacingStyle(lineSpacingStyle), + lineSpacingFactor(lineSpacingFactor), + text(text), + style(style), + angle(angle) { + + } + + /*! X Coordinate of insertion point. */ + double ipx; + /*! Y Coordinate of insertion point. */ + double ipy; + /*! Z Coordinate of insertion point. */ + double ipz; + /*! X Coordinate of X direction vector. */ + double dirx; + /*! Y Coordinate of X direction vector. */ + double diry; + /*! Z Coordinate of X direction vector. */ + double dirz; + /*! Text height */ + double height; + /*! Width of the text box. */ + double width; + /** + * Attachment point. + * + * 1 = Top left, 2 = Top center, 3 = Top right, + * 4 = Middle left, 5 = Middle center, 6 = Middle right, + * 7 = Bottom left, 8 = Bottom center, 9 = Bottom right + */ + int attachmentPoint; + /** + * Drawing direction. + * + * 1 = left to right, 3 = top to bottom, 5 = by style + */ + int drawingDirection; + /** + * Line spacing style. + * + * 1 = at least, 2 = exact + */ + int lineSpacingStyle; + /** + * Line spacing factor. 0.25 .. 4.0 + */ + double lineSpacingFactor; + /*! Text string. */ + std::string text; + /*! Style string. */ + std::string style; + /*! Rotation angle. */ + double angle; +}; + + + +/** + * Text Data. + */ +struct DXFLIB_EXPORT DL_TextData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_TextData(double ipx, double ipy, double ipz, + double apx, double apy, double apz, + double height, double xScaleFactor, + int textGenerationFlags, + int hJustification, + int vJustification, + const std::string& text, + const std::string& style, + double angle) + : ipx(ipx), ipy(ipy), ipz(ipz), + apx(apx), apy(apy), apz(apz), + height(height), xScaleFactor(xScaleFactor), + textGenerationFlags(textGenerationFlags), + hJustification(hJustification), + vJustification(vJustification), + text(text), + style(style), + angle(angle) { + } + + /*! X Coordinate of insertion point. */ + double ipx; + /*! Y Coordinate of insertion point. */ + double ipy; + /*! Z Coordinate of insertion point. */ + double ipz; + + /*! X Coordinate of alignment point. */ + double apx; + /*! Y Coordinate of alignment point. */ + double apy; + /*! Z Coordinate of alignment point. */ + double apz; + + /*! Text height */ + double height; + /*! Relative X scale factor. */ + double xScaleFactor; + /*! 0 = default, 2 = Backwards, 4 = Upside down */ + int textGenerationFlags; + /** + * Horizontal justification. + * + * 0 = Left (default), 1 = Center, 2 = Right, + * 3 = Aligned, 4 = Middle, 5 = Fit + * For 3, 4, 5 the vertical alignment has to be 0. + */ + int hJustification; + /** + * Vertical justification. + * + * 0 = Baseline (default), 1 = Bottom, 2 = Middle, 3= Top + */ + int vJustification; + /*! Text string. */ + std::string text; + /*! Style (font). */ + std::string style; + /*! Rotation angle of dimension text away from default orientation. */ + double angle; +}; + +/** + * Arc Aligned Text Data. + */ +struct DXFLIB_EXPORT DL_ArcAlignedTextData { + + /*! Text string */ + std::string text; + /*! Font name */ + std::string font; + /*! Style */ + std::string style; + + /*! X coordinate of arc center point. */ + double cx; + /*! Y coordinate of arc center point. */ + double cy; + /*! Z coordinate of arc center point. */ + double cz; + /*! Arc radius. */ + double radius; + + /*! Relative X scale factor. */ + double xScaleFactor; + /*! Text height */ + double height; + /*! Character spacing */ + double spacing; + /*! Offset from arc */ + double offset; + /*! Right offset */ + double rightOffset; + /*! Left offset */ + double leftOffset; + /*! Start angle (radians) */ + double startAngle; + /*! End angle (radians) */ + double endAngle; + /*! Reversed character order: + * false: normal + * true: reversed + */ + bool reversedCharacterOrder; + /*! Direction + * 1: outward from center + * 2: inward from center + */ + int direction; + /*! Alignment: + * 1: fit + * 2: left + * 3: right + * 4: center + */ + int alignment; + /*! Side + * 1: convex + * 2: concave + */ + int side; + /*! Bold flag */ + bool bold; + /*! Italic flag */ + bool italic; + /*! Underline flag */ + bool underline; + /*! Character set value. Windows character set identifier. */ + int characerSet; + /*! Pitch and family value. Windows pitch and character family identifier. */ + int pitch; + /*! Font type: + * false: TTF + * true: SHX + */ + bool shxFont; + /*! Wizard flag */ + bool wizard; + /*! Arc handle/ID */ + int arcHandle; +}; + +/** + * Block attribute data. + */ +struct DXFLIB_EXPORT DL_AttributeData : public DL_TextData { + DL_AttributeData(const DL_TextData& tData, const std::string& tag) + : DL_TextData(tData), tag(tag) { + + } + + /** + * Constructor. + * Parameters: see member variables. + */ + DL_AttributeData(double ipx, double ipy, double ipz, + double apx, double apy, double apz, + double height, double xScaleFactor, + int textGenerationFlags, + int hJustification, + int vJustification, + const std::string& tag, + const std::string& text, + const std::string& style, + double angle) + : DL_TextData(ipx, ipy, ipz, + apx, apy, apz, + height, xScaleFactor, + textGenerationFlags, + hJustification, + vJustification, + text, + style, + angle), + tag(tag) { + } + + /*! Tag. */ + std::string tag; +}; + + +/** + * Generic Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimensionData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimensionData(double dpx, double dpy, double dpz, + double mpx, double mpy, double mpz, + int type, + int attachmentPoint, + int lineSpacingStyle, + double lineSpacingFactor, + const std::string& text, + const std::string& style, + double angle, + double linearFactor = 1.0, + double dimScale = 1.0) : + dpx(dpx), dpy(dpy), dpz(dpz), + mpx(mpx), mpy(mpy), mpz(mpz), + type(type), + attachmentPoint(attachmentPoint), + lineSpacingStyle(lineSpacingStyle), + lineSpacingFactor(lineSpacingFactor), + text(text), + style(style), + angle(angle), + linearFactor(linearFactor), + dimScale(dimScale) { + + } + + /*! X Coordinate of definition point. */ + double dpx; + /*! Y Coordinate of definition point. */ + double dpy; + /*! Z Coordinate of definition point. */ + double dpz; + /*! X Coordinate of middle point of the text. */ + double mpx; + /*! Y Coordinate of middle point of the text. */ + double mpy; + /*! Z Coordinate of middle point of the text. */ + double mpz; + /** + * Dimension type. + * + * 0 Rotated, horizontal, or vertical + * 1 Aligned + * 2 Angular + * 3 Diametric + * 4 Radius + * 5 Angular 3-point + * 6 Ordinate + * 64 Ordinate type. This is a bit value (bit 7) + * used only with integer value 6. If set, + * ordinate is X-type; if not set, ordinate is + * Y-type + * 128 This is a bit value (bit 8) added to the + * other group 70 values if the dimension text + * has been positioned at a user-defined + * location rather than at the default location + */ + int type; + /** + * Attachment point. + * + * 1 = Top left, 2 = Top center, 3 = Top right, + * 4 = Middle left, 5 = Middle center, 6 = Middle right, + * 7 = Bottom left, 8 = Bottom center, 9 = Bottom right, + */ + int attachmentPoint; + /** + * Line spacing style. + * + * 1 = at least, 2 = exact + */ + int lineSpacingStyle; + /** + * Line spacing factor. 0.25 .. 4.0 + */ + double lineSpacingFactor; + /** + * Text string. + * + * Text string entered explicitly by user or null + * or "<>" for the actual measurement or " " (one blank space). + * for supressing the text. + */ + std::string text; + /*! Dimension style (font name). */ + std::string style; + /** + * Rotation angle of dimension text away from + * default orientation. + */ + double angle; + /** + * Linear factor style override. + */ + double linearFactor; + /** + * Dimension scale (dimscale) style override. + */ + double dimScale; +}; + + + +/** + * Aligned Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimAlignedData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimAlignedData(double depx1, double depy1, double depz1, + double depx2, double depy2, double depz2) { + + epx1 = depx1; + epy1 = depy1; + epz1 = depz1; + + epx2 = depx2; + epy2 = depy2; + epz2 = depz2; + } + + /*! X Coordinate of Extension point 1. */ + double epx1; + /*! Y Coordinate of Extension point 1. */ + double epy1; + /*! Z Coordinate of Extension point 1. */ + double epz1; + + /*! X Coordinate of Extension point 2. */ + double epx2; + /*! Y Coordinate of Extension point 2. */ + double epy2; + /*! Z Coordinate of Extension point 2. */ + double epz2; +}; + + + +/** + * Linear (rotated) Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimLinearData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimLinearData(double ddpx1, double ddpy1, double ddpz1, + double ddpx2, double ddpy2, double ddpz2, + double dAngle, double dOblique) { + + dpx1 = ddpx1; + dpy1 = ddpy1; + dpz1 = ddpz1; + + dpx2 = ddpx2; + dpy2 = ddpy2; + dpz2 = ddpz2; + + angle = dAngle; + oblique = dOblique; + } + + /*! X Coordinate of Extension point 1. */ + double dpx1; + /*! Y Coordinate of Extension point 1. */ + double dpy1; + /*! Z Coordinate of Extension point 1. */ + double dpz1; + + /*! X Coordinate of Extension point 2. */ + double dpx2; + /*! Y Coordinate of Extension point 2. */ + double dpy2; + /*! Z Coordinate of Extension point 2. */ + double dpz2; + + /*! Rotation angle (angle of dimension line) in degrees. */ + double angle; + /*! Oblique angle in degrees. */ + double oblique; +}; + + + +/** + * Radial Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimRadialData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimRadialData(double ddpx, double ddpy, double ddpz, double dleader) { + dpx = ddpx; + dpy = ddpy; + dpz = ddpz; + + leader = dleader; + } + + /*! X Coordinate of definition point. */ + double dpx; + /*! Y Coordinate of definition point. */ + double dpy; + /*! Z Coordinate of definition point. */ + double dpz; + + /*! Leader length */ + double leader; +}; + + + +/** + * Diametric Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimDiametricData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimDiametricData(double ddpx, double ddpy, double ddpz, double dleader) { + dpx = ddpx; + dpy = ddpy; + dpz = ddpz; + + leader = dleader; + } + + /*! X Coordinate of definition point (DXF 15). */ + double dpx; + /*! Y Coordinate of definition point (DXF 25). */ + double dpy; + /*! Z Coordinate of definition point (DXF 35). */ + double dpz; + + /*! Leader length */ + double leader; +}; + + + +/** + * Angular Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimAngularData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimAngularData(double ddpx1, double ddpy1, double ddpz1, + double ddpx2, double ddpy2, double ddpz2, + double ddpx3, double ddpy3, double ddpz3, + double ddpx4, double ddpy4, double ddpz4) { + + dpx1 = ddpx1; + dpy1 = ddpy1; + dpz1 = ddpz1; + + dpx2 = ddpx2; + dpy2 = ddpy2; + dpz2 = ddpz2; + + dpx3 = ddpx3; + dpy3 = ddpy3; + dpz3 = ddpz3; + + dpx4 = ddpx4; + dpy4 = ddpy4; + dpz4 = ddpz4; + } + + /*! X Coordinate of definition point 1. */ + double dpx1; + /*! Y Coordinate of definition point 1. */ + double dpy1; + /*! Z Coordinate of definition point 1. */ + double dpz1; + + /*! X Coordinate of definition point 2. */ + double dpx2; + /*! Y Coordinate of definition point 2. */ + double dpy2; + /*! Z Coordinate of definition point 2. */ + double dpz2; + + /*! X Coordinate of definition point 3. */ + double dpx3; + /*! Y Coordinate of definition point 3. */ + double dpy3; + /*! Z Coordinate of definition point 3. */ + double dpz3; + + /*! X Coordinate of definition point 4. */ + double dpx4; + /*! Y Coordinate of definition point 4. */ + double dpy4; + /*! Z Coordinate of definition point 4. */ + double dpz4; +}; + + +/** + * Angular Dimension Data (3 points version). + */ +struct DXFLIB_EXPORT DL_DimAngular3PData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimAngular3PData(double ddpx1, double ddpy1, double ddpz1, + double ddpx2, double ddpy2, double ddpz2, + double ddpx3, double ddpy3, double ddpz3) { + + dpx1 = ddpx1; + dpy1 = ddpy1; + dpz1 = ddpz1; + + dpx2 = ddpx2; + dpy2 = ddpy2; + dpz2 = ddpz2; + + dpx3 = ddpx3; + dpy3 = ddpy3; + dpz3 = ddpz3; + } + + /*! X Coordinate of definition point 1. */ + double dpx1; + /*! Y Coordinate of definition point 1. */ + double dpy1; + /*! Z Coordinate of definition point 1. */ + double dpz1; + + /*! X Coordinate of definition point 2. */ + double dpx2; + /*! Y Coordinate of definition point 2. */ + double dpy2; + /*! Z Coordinate of definition point 2. */ + double dpz2; + + /*! X Coordinate of definition point 3. */ + double dpx3; + /*! Y Coordinate of definition point 3. */ + double dpy3; + /*! Z Coordinate of definition point 3. */ + double dpz3; +}; + + + +/** + * Ordinate Dimension Data. + */ +struct DXFLIB_EXPORT DL_DimOrdinateData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_DimOrdinateData(double ddpx1, double ddpy1, double ddpz1, + double ddpx2, double ddpy2, double ddpz2, + bool dxtype) { + + dpx1 = ddpx1; + dpy1 = ddpy1; + dpz1 = ddpz1; + + dpx2 = ddpx2; + dpy2 = ddpy2; + dpz2 = ddpz2; + + xtype = dxtype; + } + + /*! X Coordinate of definition point 1. */ + double dpx1; + /*! Y Coordinate of definition point 1. */ + double dpy1; + /*! Z Coordinate of definition point 1. */ + double dpz1; + + /*! X Coordinate of definition point 2. */ + double dpx2; + /*! Y Coordinate of definition point 2. */ + double dpy2; + /*! Z Coordinate of definition point 2. */ + double dpz2; + + /*! True if the dimension indicates the X-value, false for Y-value */ + bool xtype; +}; + + + +/** + * Leader (arrow). + */ +struct DXFLIB_EXPORT DL_LeaderData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_LeaderData(int lArrowHeadFlag, + int lLeaderPathType, + int lLeaderCreationFlag, + int lHooklineDirectionFlag, + int lHooklineFlag, + double lTextAnnotationHeight, + double lTextAnnotationWidth, + int lNumber) { + + arrowHeadFlag = lArrowHeadFlag; + leaderPathType = lLeaderPathType; + leaderCreationFlag = lLeaderCreationFlag; + hooklineDirectionFlag = lHooklineDirectionFlag; + hooklineFlag = lHooklineFlag; + textAnnotationHeight = lTextAnnotationHeight; + textAnnotationWidth = lTextAnnotationWidth; + number = lNumber; + } + + /*! Arrow head flag (71). */ + int arrowHeadFlag; + /*! Leader path type (72). */ + int leaderPathType; + /*! Leader creation flag (73). */ + int leaderCreationFlag; + /*! Hookline direction flag (74). */ + int hooklineDirectionFlag; + /*! Hookline flag (75) */ + int hooklineFlag; + /*! Text annotation height (40). */ + double textAnnotationHeight; + /*! Text annotation width (41) */ + double textAnnotationWidth; + /*! Number of vertices in leader (76). */ + int number; +}; + + + +/** + * Leader Vertex Data. + */ +struct DXFLIB_EXPORT DL_LeaderVertexData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_LeaderVertexData(double px=0.0, double py=0.0, double pz=0.0) { + x = px; + y = py; + z = pz; + } + + /*! X Coordinate of the vertex. */ + double x; + /*! Y Coordinate of the vertex. */ + double y; + /*! Z Coordinate of the vertex. */ + double z; +}; + + + +/** + * Hatch data. + */ +struct DXFLIB_EXPORT DL_HatchData { + /** + * Default constructor. + */ + DL_HatchData() {} + + /** + * Constructor. + * Parameters: see member variables. + */ + DL_HatchData(int numLoops, + bool solid, + double scale, + double angle, + const std::string& pattern, + double originX = 0.0, + double originY = 0.0) : + numLoops(numLoops), + solid(solid), + scale(scale), + angle(angle), + pattern(pattern), + originX(originX), + originY(originY) { + + } + + /*! Number of boundary paths (loops). */ + int numLoops; + /*! Solid fill flag (true=solid, false=pattern). */ + bool solid; + /*! Pattern scale or spacing */ + double scale; + /*! Pattern angle in degrees */ + double angle; + /*! Pattern name. */ + std::string pattern; + /*! Pattern origin */ + double originX; + double originY; +}; + + + +/** + * Hatch boundary path (loop) data. + */ +struct DXFLIB_EXPORT DL_HatchLoopData { + /** + * Default constructor. + */ + DL_HatchLoopData() {} + /** + * Constructor. + * Parameters: see member variables. + */ + DL_HatchLoopData(int hNumEdges) { + numEdges = hNumEdges; + } + + /*! Number of edges in this loop. */ + int numEdges; +}; + + + +/** + * Hatch edge data. + */ +struct DXFLIB_EXPORT DL_HatchEdgeData { + /** + * Default constructor. + */ + DL_HatchEdgeData() : defined(false), x1(0.0), y1(0.0), x2(0.0), y2(0.0) { + } + + /** + * Constructor for a line edge. + * Parameters: see member variables. + */ + DL_HatchEdgeData(double x1, double y1, + double x2, double y2) : + defined(true), + type(1), + x1(x1), + y1(y1), + x2(x2), + y2(y2) { + } + + /** + * Constructor for an arc edge. + * Parameters: see member variables. + */ + DL_HatchEdgeData(double cx, double cy, + double radius, + double angle1, double angle2, + bool ccw) : + defined(true), + type(2), + cx(cx), + cy(cy), + radius(radius), + angle1(angle1), + angle2(angle2), + ccw(ccw) { + } + + /** + * Constructor for an ellipse arc edge. + * Parameters: see member variables. + */ + DL_HatchEdgeData(double cx, double cy, + double mx, double my, + double ratio, + double angle1, double angle2, + bool ccw) : + defined(true), + type(3), + cx(cx), + cy(cy), + angle1(angle1), + angle2(angle2), + ccw(ccw), + mx(mx), + my(my), + ratio(ratio) { + } + + /** + * Constructor for a spline edge. + * Parameters: see member variables. + */ + DL_HatchEdgeData(unsigned int degree, + bool rational, + bool periodic, + unsigned int nKnots, + unsigned int nControl, + unsigned int nFit, + const std::vector& knots, + const std::vector >& controlPoints, + const std::vector >& fitPoints, + const std::vector& weights, + double startTangentX, + double startTangentY, + double endTangentX, + double endTangentY) : + defined(true), + type(4), + degree(degree), + rational(rational), + periodic(periodic), + nKnots(nKnots), + nControl(nControl), + nFit(nFit), + controlPoints(controlPoints), + knots(knots), + weights(weights), + fitPoints(fitPoints), + startTangentX(startTangentX), + startTangentY(startTangentY), + endTangentX(endTangentX), + endTangentY(endTangentY) { + } + + /** + * Set to true if this edge is fully defined. + */ + bool defined; + + /** + * Edge type. 1=line, 2=arc, 3=elliptic arc, 4=spline. + */ + int type; + + // line edges: + + /*! Start point (X). */ + double x1; + /*! Start point (Y). */ + double y1; + /*! End point (X). */ + double x2; + /*! End point (Y). */ + double y2; + + /*! Center point of arc or ellipse arc (X). */ + double cx; + /*! Center point of arc or ellipse arc (Y). */ + double cy; + /*! Arc radius. */ + double radius; + /*! Start angle of arc or ellipse arc. */ + double angle1; + /*! End angle of arc or ellipse arc. */ + double angle2; + /*! Counterclockwise flag for arc or ellipse arc. */ + bool ccw; + + /*! Major axis end point (X). */ + double mx; + /*! Major axis end point (Y). */ + double my; + /*! Axis ratio */ + double ratio; + + + /*! Spline degree */ + unsigned int degree; + bool rational; + bool periodic; + /*! Number of knots. */ + unsigned int nKnots; + /*! Number of control points. */ + unsigned int nControl; + /*! Number of fit points. */ + unsigned int nFit; + + std::vector > controlPoints; + std::vector knots; + std::vector weights; + std::vector > fitPoints; + + double startTangentX; + double startTangentY; + + double endTangentX; + double endTangentY; + + /** Polyline boundary vertices (x y [bulge])*/ + std::vector > vertices; + //bool closed; +}; + + + +/** + * Image Data. + */ +struct DXFLIB_EXPORT DL_ImageData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_ImageData(const std::string& iref, + double iipx, double iipy, double iipz, + double iux, double iuy, double iuz, + double ivx, double ivy, double ivz, + int iwidth, int iheight, + int ibrightness, int icontrast, int ifade) { + ref = iref; + ipx = iipx; + ipy = iipy; + ipz = iipz; + ux = iux; + uy = iuy; + uz = iuz; + vx = ivx; + vy = ivy; + vz = ivz; + width = iwidth; + height = iheight; + brightness = ibrightness; + contrast = icontrast; + fade = ifade; + } + + /*! Reference to the image file + (unique, used to refer to the image def object). */ + std::string ref; + /*! X Coordinate of insertion point. */ + double ipx; + /*! Y Coordinate of insertion point. */ + double ipy; + /*! Z Coordinate of insertion point. */ + double ipz; + /*! X Coordinate of u vector along bottom of image. */ + double ux; + /*! Y Coordinate of u vector along bottom of image. */ + double uy; + /*! Z Coordinate of u vector along bottom of image. */ + double uz; + /*! X Coordinate of v vector along left side of image. */ + double vx; + /*! Y Coordinate of v vector along left side of image. */ + double vy; + /*! Z Coordinate of v vector along left side of image. */ + double vz; + /*! Width of image in pixel. */ + int width; + /*! Height of image in pixel. */ + int height; + /*! Brightness (0..100, default = 50). */ + int brightness; + /*! Contrast (0..100, default = 50). */ + int contrast; + /*! Fade (0..100, default = 0). */ + int fade; +}; + + + +/** + * Image Definition Data. + */ +struct DXFLIB_EXPORT DL_ImageDefData { + /** + * Constructor. + * Parameters: see member variables. + */ + DL_ImageDefData(const std::string& iref, + const std::string& ifile) { + ref = iref; + file = ifile; + } + + /*! Reference to the image file + (unique, used to refer to the image def object). */ + std::string ref; + + /*! Image file */ + std::string file; +}; + + + +/** + * Dictionary data. + */ +struct DXFLIB_EXPORT DL_DictionaryData { + DL_DictionaryData(const std::string& handle) : handle(handle) {} + std::string handle; +}; + + + +/** + * Dictionary entry data. + */ +struct DXFLIB_EXPORT DL_DictionaryEntryData { + DL_DictionaryEntryData(const std::string& name, const std::string& handle) : + name(name), handle(handle) {} + + std::string name; + std::string handle; +}; + +#endif + +// EOF diff --git a/datafile/dxf/dxflib/dl_exception.h b/datafile/dxf/dxflib/dl_exception.h new file mode 100644 index 0000000..7fd944b --- /dev/null +++ b/datafile/dxf/dxflib/dl_exception.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** Copyright (C) 2001 Robert J. Campbell Jr. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_EXCEPTION_H +#define DL_EXCEPTION_H + +#include "dl_global.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/** + * Used for exception handling. + */ +class DXFLIB_EXPORT DL_Exception {} +; + +/** + * Used for exception handling. + */ +class DXFLIB_EXPORT DL_NullStrExc : public DL_Exception {} +; + +/** + * Used for exception handling. + */ +class DXFLIB_EXPORT DL_GroupCodeExc : public DL_Exception { + DL_GroupCodeExc(int gc=0) : groupCode(gc) {} + int groupCode; +}; +#endif + diff --git a/datafile/dxf/dxflib/dl_extrusion.h b/datafile/dxf/dxflib/dl_extrusion.h new file mode 100644 index 0000000..d836c04 --- /dev/null +++ b/datafile/dxf/dxflib/dl_extrusion.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_EXTRUSION_H +#define DL_EXTRUSION_H + +#include "dl_global.h" + +#include + + +/** + * Extrusion direction. + * + * @author Andrew Mustun + */ +class DXFLIB_EXPORT DL_Extrusion { + +public: + + /** + * Default constructor. + */ + DL_Extrusion() { + direction = new double[3]; + setDirection(0.0, 0.0, 1.0); + setElevation(0.0); + } + + + /** + * Destructor. + */ + ~DL_Extrusion() { + delete[] direction ; + } + + + /** + * Constructor for DXF extrusion. + * + * @param direction Vector of axis along which the entity shall be extruded + * this is also the Z axis of the Entity coordinate system + * @param elevation Distance of the entities XY plane from the origin of the + * world coordinate system + */ + DL_Extrusion(double dx, double dy, double dz, double elevation) { + direction = new double[3]; + setDirection(dx, dy, dz); + setElevation(elevation); + } + + + + /** + * Sets the direction vector. + */ + void setDirection(double dx, double dy, double dz) { + direction[0]=dx; + direction[1]=dy; + direction[2]=dz; + } + + + + /** + * @return direction vector. + */ + double* getDirection() const { + return direction; + } + + + + /** + * @return direction vector. + */ + void getDirection(double dir[]) const { + dir[0]=direction[0]; + dir[1]=direction[1]; + dir[2]=direction[2]; + } + + + + /** + * Sets the elevation. + */ + void setElevation(double elevation) { + this->elevation = elevation; + } + + + + /** + * @return Elevation. + */ + double getElevation() const { + return elevation; + } + + + + /** + * Copies extrusion (deep copies) from another extrusion object. + */ + DL_Extrusion operator = (const DL_Extrusion& extru) { + setDirection(extru.direction[0], extru.direction[1], extru.direction[2]); + setElevation(extru.elevation); + + return *this; + } + + + +private: + double *direction; + double elevation; +}; + +#endif + diff --git a/datafile/dxf/dxflib/dl_global.h b/datafile/dxf/dxflib/dl_global.h new file mode 100644 index 0000000..0d52bea --- /dev/null +++ b/datafile/dxf/dxflib/dl_global.h @@ -0,0 +1,13 @@ +#if defined(DXFLIB_DLL) +# ifdef _WIN32 +# if defined(DXFLIB_LIBRARY) +# define DXFLIB_EXPORT __declspec(dllexport) +# else +# define DXFLIB_EXPORT __declspec(dllimport) +# endif +# else +# define DXFLIB_EXPORT +# endif +#else +# define DXFLIB_EXPORT +#endif diff --git a/datafile/dxf/dxflib/dl_writer.h b/datafile/dxf/dxflib/dl_writer.h new file mode 100644 index 0000000..2aa09d5 --- /dev/null +++ b/datafile/dxf/dxflib/dl_writer.h @@ -0,0 +1,654 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** Copyright (C) 2001 Robert J. Campbell Jr. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef DL_WRITER_H +#define DL_WRITER_H + +#include "dl_global.h" + +#ifndef _WIN32 +#include +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include + +#include "dl_attributes.h" +#include "dl_codes.h" + + + +/** + * Defines interface for writing low level DXF constructs to + * a file. Implementation is defined in derived classes that write + * to binary or ASCII files. + * + * Implements functions that write higher level constructs in terms of + * the low level ones. + * + * @todo Add error checking for string/entry length. + */ +class DXFLIB_EXPORT DL_Writer { +public: + /** + * @param version DXF version. Defaults to DL_VERSION_2002. + */ + DL_Writer(DL_Codes::version version) : m_handle(0x30) { + this->version = version; + modelSpaceHandle = 0; + paperSpaceHandle = 0; + paperSpace0Handle = 0; + } + + virtual ~DL_Writer() {} + ; + + /** Generic section for section 'name'. + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  name
+     * 
+ */ + void section(const char* name) const { + dxfString(0, "SECTION"); + dxfString(2, name); + } + + /** + * Section HEADER + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  HEADER
+     * 
+ */ + void sectionHeader() const { + section("HEADER"); + } + + /** + * Section TABLES + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  TABLES
+     * 
+ */ + void sectionTables() const { + section("TABLES"); + } + + /** + * Section BLOCKS + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  BLOCKS
+     * 
+ */ + void sectionBlocks() const { + section("BLOCKS"); + } + + /** + * Section ENTITIES + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  ENTITIES
+     * 
+ */ + void sectionEntities() const { + section("ENTITIES"); + } + + /** + * Section CLASSES + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  CLASSES
+     * 
+ */ + void sectionClasses() const { + section("CLASSES"); + } + + /** + * Section OBJECTS + * + *
+     *   0
+     *  SECTION
+     *   2
+     *  OBJECTS
+     * 
+ */ + void sectionObjects() const { + section("OBJECTS"); + } + + /** + * End of a section. + * + *
+     *   0
+     *  ENDSEC
+     * 
+ */ + void sectionEnd() const { + dxfString(0, "ENDSEC"); + } + + /** + * Generic table for table 'name' with 'num' entries: + * + *
+     *   0
+     *  TABLE
+     *   2
+     *  name
+     *  70
+     *   num
+     * 
+ */ + void table(const char* name, int num, int h=0) const { + dxfString(0, "TABLE"); + dxfString(2, name); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } + else { + dxfHex(5, h); + } + dxfString(100, "AcDbSymbolTable"); + } + dxfInt(70, num); + } + + /** Table for layers. + * + * @param num Number of layers in total. + * + *
+     *   0
+     *  TABLE
+     *   2
+     *  LAYER
+     *   70
+     *      num
+     * 
+ */ + void tableLayers(int num) const { + table("LAYER", num, 2); + } + + /** Table for line types. + * + * @param num Number of line types in total. + * + *
+     *   0
+     *  TABLE
+     *   2
+     *  LTYPE
+     *   70
+     *      num
+     * 
+ */ + void tableLinetypes(int num) const { + //linetypeHandle = 5; + table("LTYPE", num, 5); + } + + /** Table for application id. + * + * @param num Number of registered applications in total. + * + *
+     *   0
+     *  TABLE
+     *   2
+     *  APPID
+     *   70
+     *      num
+     * 
+ */ + void tableAppid(int num) const { + table("APPID", num, 9); + } + + /** Table for text style. + * + * @param num Number of text styles. + * + *
+     *   0
+     *  TABLE
+     *   2
+     *  STYLE
+     *   70
+     *      num
+     * 
+ */ + void tableStyle(int num) const { + table("STYLE", num, 3); + } + + /** + * End of a table. + * + *
+     *   0
+     *  ENDTAB
+     * 
+ */ + void tableEnd() const { + dxfString(0, "ENDTAB"); + } + + /** + * End of the DXF file. + * + *
+     *   0
+     *  EOF
+     * 
+ */ + void dxfEOF() const { + dxfString(0, "EOF"); + } + + /** + * Comment. + * + *
+     *  999
+     *  text
+     * 
+ */ + void comment(const char* text) const { + dxfString(999, text); + } + + /** + * Entity. + * + *
+     *   0
+     *  entTypeName
+     * 
+ * + * @return Unique handle or 0. + */ + void entity(const char* entTypeName) const { + dxfString(0, entTypeName); + if (version>=DL_VERSION_2000) { + handle(); + } + } + + /** + * Attributes of an entity. + * + *
+     *   8
+     *  layer
+     *  62
+     *  color
+     *  39
+     *  width
+     *   6
+     *  linetype
+     * 
+ */ + void entityAttributes(const DL_Attributes& attrib) const { + + // layer name: + dxfString(8, attrib.getLayer()); + + // R12 doesn't accept BYLAYER values. The value has to be missing + // in that case. + if (version>=DL_VERSION_2000 || attrib.getColor()!=256) { + dxfInt(62, attrib.getColor()); + } + if (version>=DL_VERSION_2000 && attrib.getColor24()!=-1) { + dxfInt(420, attrib.getColor24()); + } + if (version>=DL_VERSION_2000) { + dxfInt(370, attrib.getWidth()); + } + if (version>=DL_VERSION_2000) { + dxfReal(48, attrib.getLinetypeScale()); + } + std::string linetype = attrib.getLinetype(); + std::transform(linetype.begin(), linetype.end(), linetype.begin(), ::toupper); + if (version>=DL_VERSION_2000 || linetype=="BYLAYER") { + dxfString(6, attrib.getLinetype()); + } + } + + /** + * Subclass. + */ + void subClass(const char* sub) const { + dxfString(100, sub); + } + + /** + * Layer (must be in the TABLES section LAYER). + * + *
+     *   0
+     *  LAYER
+     * 
+ */ + void tableLayerEntry(unsigned long int h=0) const { + dxfString(0, "LAYER"); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } else { + dxfHex(5, h); + } + dxfString(100, "AcDbSymbolTableRecord"); + dxfString(100, "AcDbLayerTableRecord"); + } + } + + /** + * Line type (must be in the TABLES section LTYPE). + * + *
+     *   0
+     *  LTYPE
+     * 
+ */ + void tableLinetypeEntry(unsigned long int h=0) const { + dxfString(0, "LTYPE"); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } else { + dxfHex(5, h); + } + //dxfHex(330, 0x5); + dxfString(100, "AcDbSymbolTableRecord"); + dxfString(100, "AcDbLinetypeTableRecord"); + } + } + + /** + * Appid (must be in the TABLES section APPID). + * + *
+     *   0
+     *  APPID
+     * 
+ */ + void tableAppidEntry(unsigned long int h=0) const { + dxfString(0, "APPID"); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } else { + dxfHex(5, h); + } + //dxfHex(330, 0x9); + dxfString(100, "AcDbSymbolTableRecord"); + dxfString(100, "AcDbRegAppTableRecord"); + } + } + + /** + * Block (must be in the section BLOCKS). + * + *
+     *   0
+     *  BLOCK
+     * 
+ */ + void sectionBlockEntry(unsigned long int h=0) const { + dxfString(0, "BLOCK"); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } else { + dxfHex(5, h); + } + //dxfHex(330, blockHandle); + dxfString(100, "AcDbEntity"); + if (h==0x1C) { + dxfInt(67, 1); + } + dxfString(8, "0"); // TODO: Layer for block + dxfString(100, "AcDbBlockBegin"); + } + } + + /** + * End of Block (must be in the section BLOCKS). + * + *
+     *   0
+     *  ENDBLK
+     * 
+ */ + void sectionBlockEntryEnd(unsigned long int h=0) const { + dxfString(0, "ENDBLK"); + if (version>=DL_VERSION_2000) { + if (h==0) { + handle(); + } else { + dxfHex(5, h); + } + //dxfHex(330, blockHandle); + dxfString(100, "AcDbEntity"); + if (h==0x1D) { + dxfInt(67, 1); + } + dxfString(8, "0"); // TODO: Layer for block + dxfString(100, "AcDbBlockEnd"); + } + } + + void color(int col=256) const { + dxfInt(62, col); + } + void linetype(const char *lt) const { + dxfString(6, lt); + } + void linetypeScale(double scale) const { + dxfReal(48, scale); + } + void lineWeight(int lw) const { + dxfInt(370, lw); + } + + void coord(int gc, double x, double y, double z=0) const { + dxfReal(gc, x); + dxfReal(gc+10, y); + dxfReal(gc+20, z); + } + + void coordTriplet(int gc, const double* value) const { + if (value) { + dxfReal(gc, *value++); + dxfReal(gc+10, *value++); + dxfReal(gc+20, *value++); + } + } + + void resetHandle() const { + m_handle = 1; + } + + /** + * Writes a unique handle and returns it. + */ + unsigned long handle(int gc=5) const { + // handle has to be hex + dxfHex(gc, m_handle); + return m_handle++; + } + + /** + * @return Next handle that will be written. + */ + unsigned long getNextHandle() const { + return m_handle; + } + + /** + * Increases handle, so that the handle returned remains available. + */ + unsigned long incHandle() const { + return m_handle++; + } + + /** + * Sets the handle of the model space. Entities refer to + * this handle. + */ + void setModelSpaceHandle(unsigned long h) { + modelSpaceHandle = h; + } + + unsigned long getModelSpaceHandle() { + return modelSpaceHandle; + } + + /** + * Sets the handle of the paper space. Some special blocks refer to + * this handle. + */ + void setPaperSpaceHandle(unsigned long h) { + paperSpaceHandle = h; + } + + unsigned long getPaperSpaceHandle() { + return paperSpaceHandle; + } + + /** + * Sets the handle of the paper space 0. Some special blocks refer to + * this handle. + */ + void setPaperSpace0Handle(unsigned long h) { + paperSpace0Handle = h; + } + + unsigned long getPaperSpace0Handle() { + return paperSpace0Handle; + } + + /** + * Must be overwritten by the implementing class to write a + * real value to the file. + * + * @param gc Group code. + * @param value The real value. + */ + virtual void dxfReal(int gc, double value) const = 0; + + /** + * Must be overwritten by the implementing class to write an + * int value to the file. + * + * @param gc Group code. + * @param value The int value. + */ + virtual void dxfInt(int gc, int value) const = 0; + + /** + * Can be overwritten by the implementing class to write a + * bool value to the file. + * + * @param gc Group code. + * @param value The bool value. + */ + virtual void dxfBool(int gc, bool value) const { + dxfInt(gc, (int)value); + } + + /** + * Must be overwritten by the implementing class to write an + * int value (hex) to the file. + * + * @param gc Group code. + * @param value The int value. + */ + virtual void dxfHex(int gc, int value) const = 0; + + /** + * Must be overwritten by the implementing class to write a + * string to the file. + * + * @param gc Group code. + * @param value The string. + */ + virtual void dxfString(int gc, const char* value) const = 0; + + /** + * Must be overwritten by the implementing class to write a + * string to the file. + * + * @param gc Group code. + * @param value The string. + */ + virtual void dxfString(int gc, const std::string& value) const = 0; + +protected: + mutable unsigned long m_handle; + mutable unsigned long modelSpaceHandle; + mutable unsigned long paperSpaceHandle; + mutable unsigned long paperSpace0Handle; + + /** + * DXF version to be created. + */ + DL_Codes::version version; +private: +}; + +#endif diff --git a/datafile/dxf/dxflib/dl_writer_ascii.cpp b/datafile/dxf/dxflib/dl_writer_ascii.cpp new file mode 100644 index 0000000..199707a --- /dev/null +++ b/datafile/dxf/dxflib/dl_writer_ascii.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** Copyright (C) 2001-2013 RibbonSoft, GmbH. All rights reserved. +** Copyright (C) 2001 Robert J. Campbell Jr. +** +** This file is part of the dxflib project. +** +** This file 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. +** +** Licensees holding valid dxflib Professional Edition licenses may use +** this file in accordance with the dxflib Commercial License +** Agreement provided with the Software. +** +** 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.ribbonsoft.com for further details. +** +** Contact info@ribbonsoft.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include +#include + +#include "dl_writer_ascii.h" +#include "dl_exception.h" + + +/** + * Closes the output file. + */ +void DL_WriterA::close() const { + m_ofile.close(); +} + + +/** + * @retval true Opening file has failed. + * @retval false Otherwise. + */ +bool DL_WriterA::openFailed() const { + return m_ofile.fail(); +} + + + +/** + * Writes a real (double) variable to the DXF file. + * + * @param gc Group code. + * @param value Double value + */ +void DL_WriterA::dxfReal(int gc, double value) const { + char str[256]; + if (version==DL_Codes::AC1009_MIN) { + sprintf(str, "%.6lf", value); + } + else { + sprintf(str, "%.16lf", value); + } + + // fix for german locale: + strReplace(str, ',', '.'); + + // Cut away those zeros at the end: + bool dot = false; + int end = -1; + for (unsigned int i=0; i0 && end<(int)strlen(str)) { + str[end] = '\0'; + } + + dxfString(gc, str); + m_ofile.flush(); +} + + + +/** + * Writes an int variable to the DXF file. + * + * @param gc Group code. + * @param value Int value + */ +void DL_WriterA::dxfInt(int gc, int value) const { + m_ofile << (gc<10 ? " " : (gc<100 ? " " : "")) << gc << "\n" << value << "\n"; +} + + + +/** + * Writes a hex int variable to the DXF file. + * + * @param gc Group code. + * @param value Int value + */ +void DL_WriterA::dxfHex(int gc, int value) const { + char str[12]; + sprintf(str, "%0X", value); + dxfString(gc, str); +} + + + +/** + * Writes a string variable to the DXF file. + * + * @param gc Group code. + * @param value String + */ +void DL_WriterA::dxfString(int gc, const char* value) const { + if (value==NULL) { +#ifndef __GCC2x__ + //throw DL_NullStrExc(); +#endif + } + m_ofile << (gc<10 ? " " : (gc<100 ? " " : "")) << gc << "\n" + << value << "\n"; +} + + + +void DL_WriterA::dxfString(int gc, const std::string& value) const { + m_ofile << (gc<10 ? " " : (gc<100 ? " " : "")) << gc << "\n" + << value << "\n"; +} + + +/** + * Replaces every occurence of src with dest in the null terminated str. + */ +void DL_WriterA::strReplace(char* str, char src, char dest) { + size_t i; + for (i=0; i 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "dl_writer.h" +#include +#include + +/** + * Implements functions defined in DL_Writer for writing low + * level DXF constructs to an ASCII format DXF file. + * + * @para fname File name of the file to be created. + * @para version DXF version. Defaults to DL_VERSION_2002. + * + * @todo What if \c fname is NULL? Or \c fname can't be opened for + * another reason? + */ +class DXFLIB_EXPORT DL_WriterA : public DL_Writer { +public: + DL_WriterA(const char* fname, DL_Codes::version version=DL_VERSION_2000) + : DL_Writer(version), m_ofile(fname) {} + virtual ~DL_WriterA() {} + + bool openFailed() const; + void close() const; + void dxfReal(int gc, double value) const; + void dxfInt(int gc, int value) const; + void dxfHex(int gc, int value) const; + void dxfString(int gc, const char* value) const; + void dxfString(int gc, const std::string& value) const; + + static void strReplace(char* str, char src, char dest); + +private: + /** + * DXF file to be created. + */ + mutable std::ofstream m_ofile; + +}; + +#endif + diff --git a/datafile/dxf/dxfreader.cpp b/datafile/dxf/dxfreader.cpp new file mode 100644 index 0000000..24db047 --- /dev/null +++ b/datafile/dxf/dxfreader.cpp @@ -0,0 +1,379 @@ +#include "dxfreader.h" +#include + +DxfReader::DxfReader(const QString &fileName, QObject *parent) + : QObject(parent) + , fileName(fileName) +{ + //QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK")); + + // 读取 dxf 文件 + DL_Dxf *dxf = new DL_Dxf; + if (!dxf->in(std::string(fileName.toLocal8Bit()), this)) { // if file open failed + std::cerr << std::string(fileName.toLocal8Bit()) << " could not be opened.\n"; + return; + } + delete dxf; + dxf = nullptr; +} + +void DxfReader::addText(const DL_TextData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfText << data; +} + +void DxfReader::addLine(const DL_LineData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfLines << data; +} + +void DxfReader::addArc(const DL_ArcData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfArcs << data; +} + +void DxfReader::addCircle(const DL_CircleData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfCircles << data; +} + +void DxfReader::addEllipse(const DL_EllipseData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfEllipses << data; +} + +void DxfReader::addPolyline(const DL_PolylineData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfPolylines << data; +} + +void DxfReader::addPoint(const DL_PointData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfPoints << data; +} + +void DxfReader::addSpline(const DL_SplineData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfSplines << data; +} + +void DxfReader::addBlock(const DL_BlockData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfBlocks << data; +} + +void DxfReader::endBlock() +{ + +} + +void DxfReader::addLayer(const DL_LayerData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfLayers << data; +} + +void DxfReader::addLinetype(const DL_LinetypeData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfLinetypes << data; +} + +void DxfReader::addLinetypeDash(double length) +{ + if(length < 0){} +} + +void DxfReader::addXLine(const DL_XLineData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfXLines << data; +} + +void DxfReader::addRay(const DL_RayData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfRays << data; +} + +void DxfReader::addVertex(const DL_VertexData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfVertexs << data; +} + +void DxfReader::addControlPoint(const DL_ControlPointData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfControlPoints << data; +} + +void DxfReader::addFitPoint(const DL_FitPointData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfFitPoints << data; +} + +void DxfReader::addKnot(const DL_KnotData &data) +{ + if(data.k == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addInsert(const DL_InsertData &data) +{ + if(data.angle == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addSolid(const DL_SolidData &data) +{ + if(data.x == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addTrace(const DL_TraceData &data) +{ + if(data.x == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addTextStyle(const DL_StyleData &data) +{ + if(data.flags == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addMTextChunk(const std::string &text) +{ + if(text.data() == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addMText(const DL_MTextData &data) +{ + if(data.angle == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addArcAlignedText(const DL_ArcAlignedTextData &data) +{ + if(data.alignment == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addAttribute(const DL_AttributeData &data) +{ + if(data.angle == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimAlign(const DL_DimensionData &data, const DL_DimAlignedData &edata) +{ + if(data.angle == 0){} + if(edata.epx1 == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimLinear(const DL_DimensionData &data, const DL_DimLinearData &edata) +{ + if(data.angle == 0){} + if(edata.angle == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimRadial(const DL_DimensionData &data, const DL_DimRadialData &edata) +{ + if(data.angle == 0){} + if(edata.dpx == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimDiametric(const DL_DimensionData &data, const DL_DimDiametricData &edata) +{ + if(data.angle == 0){} + if(edata.dpx == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimAngular(const DL_DimensionData &data, const DL_DimAngularData &edata) +{ + if(data.angle == 0){} + if(edata.dpx1 == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimAngular3P(const DL_DimensionData &data, const DL_DimAngular3PData &edata) +{ + if(data.angle == 0){} + if(edata.dpx1 == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDimOrdinate(const DL_DimensionData &data, const DL_DimOrdinateData &edata) +{ + if(data.angle == 0){} + if(edata.dpx1 == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addLeader(const DL_LeaderData &data) +{ + if(data.arrowHeadFlag == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addLeaderVertex(const DL_LeaderVertexData &data) +{ + if(data.x == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addHatch(const DL_HatchData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfHatchs << data; +} + +void DxfReader::addHatchLoop(const DL_HatchLoopData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfHatchLoops << data; +} + +void DxfReader::addHatchEdge(const DL_HatchEdgeData &data) +{ + //qDebug() << Q_FUNC_INFO; + dxfHatchEdges << data; +} + +void DxfReader::addImage(const DL_ImageData &data) +{ + if(data.brightness == 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::linkImage(const DL_ImageDefData &data) +{ + if(data.file == ""){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addXRecord(const std::string &handle) +{ + if(handle.length() <= 0){} +} + +void DxfReader::addXRecordString(int code, const std::string &value) +{ + if(code <= 0){} + if(value.length() <= 0){} +} + +void DxfReader::addXRecordReal(int code, double value) +{ + if(code <= 0){} + if(value <= 0){} +} + +void DxfReader::addXRecordInt(int code, int value) +{ + if(code <= 0){} + if(value <= 0){} +} + +void DxfReader::addXRecordBool(int code, bool value) +{ + if(code <= 0){} + if(value <= 0){} +} + +void DxfReader::addXDataApp(const std::string &appId) +{ + if(appId.length() <= 0){} +} + +void DxfReader::addXDataString(int code, const std::string &value) +{ + if(code <= 0){} + if(value.length() <= 0){} +} + +void DxfReader::addXDataReal(int code, double value) +{ + if(code <= 0){} + if(value <= 0){} +} + +void DxfReader::addXDataInt(int code, int value) +{ + if(code <= 0){} + if(value <= 0){} +} + +void DxfReader::addDictionary(const DL_DictionaryData &data) +{ + if(data.handle.length() <= 0){} +// qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addDictionaryEntry(const DL_DictionaryEntryData &data) +{ + if(data.handle.length() <= 0){} +// qDebug() << Q_FUNC_INFO; +} + +void DxfReader::setVariableVector(const std::string &key, double v1, double v2, double v3, int code) +{ + if(key.length() <= 0){} + if(v1 <= 0){} + if(v2 <= 0){} + if(v3 <= 0){} + if(code <= 0){} +} + +void DxfReader::setVariableString(const std::string &key, const std::string &value, int code) +{ + if(key.length() <= 0){} + if(value.length() <= 0){} + if(code <= 0){} +} + +void DxfReader::setVariableInt(const std::string &key, int value, int code) +{ + if(key.length() <= 0){} + if(value <= 0){} + if(code <= 0){} +} + +void DxfReader::setVariableDouble(const std::string &key, double value, int code) +{ + if(key.length() <= 0){} + if(value <= 0){} + if(code <= 0){} +} + +void DxfReader::add3dFace(const DL_3dFaceData &data) +{ + if(data.thickness <= 0){} + //qDebug() << Q_FUNC_INFO; +} + +void DxfReader::addComment(const std::string &comment) +{ + if(comment.length() <= 0){} +} + +void DxfReader::endSequence() +{ + //qDebug() << Q_FUNC_INFO; +} diff --git a/datafile/dxf/dxfreader.h b/datafile/dxf/dxfreader.h new file mode 100644 index 0000000..7152e50 --- /dev/null +++ b/datafile/dxf/dxfreader.h @@ -0,0 +1,112 @@ +#ifndef DXFREADER_H +#define DXFREADER_H + +#include +#include +#include "dxflib/dl_dxf.h" +#include "dxflib/dl_creationadapter.h" + +#include +#include + +class DxfReader : public QObject, public DL_CreationAdapter +{ + Q_OBJECT +public: + struct DxfText { + QString Text; + }; + explicit DxfReader(const QString &fileName, QObject *parent = nullptr); + + virtual void addText(const DL_TextData& data) override; + virtual void addLine(const DL_LineData& data) override; + virtual void addArc(const DL_ArcData& data) override; + virtual void addCircle(const DL_CircleData& data) override; + virtual void addEllipse(const DL_EllipseData& data) override; + virtual void addPolyline(const DL_PolylineData& data) override; + virtual void addPoint(const DL_PointData& data) override; + virtual void addSpline(const DL_SplineData& data) override; + virtual void addBlock(const DL_BlockData& data) override; + virtual void endBlock() override; + + virtual void addLayer(const DL_LayerData& data) override; + virtual void addLinetype(const DL_LinetypeData& data) override; + virtual void addLinetypeDash(double length) override; + virtual void addXLine(const DL_XLineData& data) override; + virtual void addRay(const DL_RayData& data) override; + virtual void addVertex(const DL_VertexData& data) override; + virtual void addControlPoint(const DL_ControlPointData& data) override; + virtual void addFitPoint(const DL_FitPointData& data) override; + virtual void addKnot(const DL_KnotData& data) override; + virtual void addInsert(const DL_InsertData& data) override; + virtual void addSolid(const DL_SolidData& data) override; + virtual void addTrace(const DL_TraceData& data) override; + virtual void addTextStyle(const DL_StyleData& data) override; + virtual void addMTextChunk(const std::string& text) override; + virtual void addMText(const DL_MTextData& data) override; + virtual void addArcAlignedText(const DL_ArcAlignedTextData& data) override; + virtual void addAttribute(const DL_AttributeData& data) override; + virtual void addDimAlign(const DL_DimensionData& data, const DL_DimAlignedData& edata) override; + virtual void addDimLinear(const DL_DimensionData& data, const DL_DimLinearData& edata) override; + virtual void addDimRadial(const DL_DimensionData& data, const DL_DimRadialData& edata) override; + virtual void addDimDiametric(const DL_DimensionData& data, const DL_DimDiametricData& edata) override; + virtual void addDimAngular(const DL_DimensionData& data, const DL_DimAngularData& edata) override; + virtual void addDimAngular3P(const DL_DimensionData& data, const DL_DimAngular3PData& edata) override; + virtual void addDimOrdinate(const DL_DimensionData& data, const DL_DimOrdinateData& edata) override; + virtual void addLeader(const DL_LeaderData &data) override; + virtual void addLeaderVertex(const DL_LeaderVertexData &data) override; + virtual void addHatch(const DL_HatchData& data) override; + virtual void addHatchLoop(const DL_HatchLoopData& data) override; + virtual void addHatchEdge(const DL_HatchEdgeData& data) override; + virtual void addImage(const DL_ImageData &data) override; + virtual void linkImage(const DL_ImageDefData &data) override; + + virtual void addXRecord(const std::string& handle) override; + virtual void addXRecordString(int code, const std::string& value) override; + virtual void addXRecordReal(int code, double value) override; + virtual void addXRecordInt(int code, int value) override; + virtual void addXRecordBool(int code, bool value) override; + + virtual void addXDataApp(const std::string& appId) override; + virtual void addXDataString(int code, const std::string& value) override; + virtual void addXDataReal(int code, double value) override; + virtual void addXDataInt(int code, int value) override; + + virtual void addDictionary(const DL_DictionaryData& data) override; + virtual void addDictionaryEntry(const DL_DictionaryEntryData& data) override; + + virtual void setVariableVector(const std::string& key, double v1, double v2, double v3, int code) override; + virtual void setVariableString(const std::string& key, const std::string& value, int code) override; + virtual void setVariableInt(const std::string& key, int value, int code) override; + virtual void setVariableDouble(const std::string& key, double value, int code) override; + + virtual void add3dFace(const DL_3dFaceData &data) override; + virtual void addComment(const std::string &comment) override; + virtual void endSequence() override; + + QList dxfLines; + QList dxfText; + QList dxfArcs; + QList dxfCircles; + QList dxfEllipses; + QList dxfPolylines; + QList dxfPoints; + QList dxfSplines; + QList dxfBlocks; + QList dxfVertexs; + QList dxfLayers; + QList dxfLinetypes; + QList dxfXLines; + QList dxfRays; + QList dxfControlPoints; + QList dxfFitPoints; + QList dxfHatchs; + QList dxfHatchLoops; + QList dxfHatchEdges; + +private: + QString fileName; + +}; + +#endif // DXFREADER_H diff --git a/datafile/hpgl.7z b/datafile/hpgl.7z new file mode 100644 index 0000000000000000000000000000000000000000..3226475c8848c135c26421f0bcc98de0b3b2efa8 GIT binary patch literal 37050 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

ftRqJf#~jlrv@n1 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 literal 0 HcmV?d00001 diff --git a/datafile/hpgl/importhpgl.cpp b/datafile/hpgl/importhpgl.cpp new file mode 100644 index 0000000..fbb4716 --- /dev/null +++ b/datafile/hpgl/importhpgl.cpp @@ -0,0 +1,2430 @@ +#include "importhpgl.h" +#include +#include +#include +#include +#include "vectorfont.h" + +ImportHPGL::ImportHPGL(QObject *parent) : + QObject(parent) +{ + m_iDPMM = 40; + m_iPenNo = 1; + m_ptCurrentPos = QPoint(0,0); + m_lineType.bDefault = true; + m_bPenUp = true; + + m_pMarker = NULL; + m_dScale = (double)1.0; + + m_chTerminator = 3; + m_nTerminatorMode = 1; + + m_listXY.clear(); + + m_penPen.setColor(QColor(0,0,0)); + m_cutPen.setColor(QColor(0,255,0)); + m_halfCutPen.setColor(QColor(0,0,255)); + + m_dTextHeight = 0.375 * 10 * m_iDPMM;//字的高度 + m_dTextWidth = 0.285 * 10 * m_iDPMM;//字的宽度 + m_nLableOrigin = 1;//字符串相对于原点位置 + m_dTextAngle = 0;//指定每行文本输出时相对于设备x轴的角度,其单位为1/10度 + + m_dScaleX = 1; + m_dScaleY = 1; + m_ptOrigin = QPoint(0,0); + m_nLength = 0; + m_bPage = false; + m_bFontItalic = false; + m_iFontSize = 0; + m_strFontName = ""; + + m_pFileBuf = NULL; +} + +ImportHPGL::~ImportHPGL() +{ +} + +int ImportHPGL::GetQRVesion(int nCount) +{ + int nVesion = 1; + + if (nCount < 17) + { + nVesion = 1; + } + else if ((nCount >= 17) && (nCount < 32)) + { + nVesion = 2; + } + else if ((nCount >= 32) && (nCount < 53)) + { + nVesion = 3; + } + else if ((nCount >= 53) && (nCount < 78)) + { + nVesion = 4; + } + else if ((nCount >= 78) && (nCount < 106)) + { + nVesion = 5; + } + else if ((nCount >= 106) && (nCount < 134)) + { + nVesion = 6; + } + else if ((nCount >= 134) && (nCount < 154)) + { + nVesion = 7; + } + else if ((nCount >= 154) && (nCount < 192)) + { + nVesion = 8; + } + else if ((nCount >= 192) && (nCount < 230)) + { + nVesion = 9; + } + else if ((nCount >= 230) && (nCount < 271)) + { + nVesion = 10; + } + else + { + nVesion = 40; + } + return nVesion; +} + +void ImportHPGL::PointRotate(QPoint &ptPoint, QPoint ptPointO, double dSinBeta, double dCosBeta) +{ + int tx = ptPoint.x() - ptPointO.x(); + int ty = ptPoint.y() - ptPointO.y(); + + int nx = tx*dCosBeta - ty*dSinBeta; + int ny = tx*dSinBeta + ty*dCosBeta; + + ptPoint.setX(nx); + ptPoint.setY(ny); +} + +void ImportHPGL::IniPara() +{ + m_iPenNo = 1; + m_ptCurrentPos = QPoint(0,0); + m_lineType.bDefault = true; + m_bPenUp = true; + + m_pMarker=NULL; + m_dScale=(double)1.0; + + m_chTerminator = 3; + m_nTerminatorMode = 1; + + m_listXY.clear(); + + m_dTextHeight = 0.375 * 10 * m_iDPMM;//字的高度 + m_dTextWidth = 0.285 * 10 * m_iDPMM;//字的宽度 + m_nLableOrigin = 1;//字符串相对于原点位置 + m_dTextAngle = 0;//指定每行文本输出时相对于设备x轴的角度,其单位为1/10度 + + m_dScaleX = 1; + m_dScaleY = 1; + m_ptOrigin = QPoint(0,0); + m_nLength = 0; + m_bPage = false; + m_lineType.bDefault = true; +} + +bool ImportHPGL::Read(QString strPathName,Marker *pMarker) +{ + QFile file(strPathName); + char c; + bool bOk; + + if(!file.open(QIODevice::ReadOnly)) + { + qDebug() <<"file open failed"; + return false; + } + + m_pMarker=pMarker; + + m_dScale=(double)m_pMarker->m_iDPMM / m_iDPMM; + m_listXY.clear(); + m_nFileLength = file.size(); + m_pFileBuf = new char[m_nFileLength]; + file.read(m_pFileBuf,m_nFileLength); + file.close(); + m_nCharCount = 0; + bOk=GetChar(&c); + while (bOk && m_nCharCount < m_nFileLength) + { + switch (c) + { + case 'S': //S命令 + case 's': + bOk=S_Code(); + break; + case 'I': //I命令 + case 'i': + bOk=I_Code(); + break; + case 'P': //P命令 + case 'p': + bOk=P_Code(); + break; + case 'L': //L命令 + case 'l': + bOk=L_Code(); + break; + case 'D': + case 'd': + bOk=D_Code(); + break; + case 'C': + case 'c': + bOk=C_Code(); + break; + case ';': + case ' ': + case 0x0A: + case 0x0D: + break; + default: + bOk = MoveToNextEnglishChar(); + break; + } + + if (bOk) + { + bOk=GetChar(&c); + if (m_nCharCount == m_nFileLength) bOk=true; + } + } + + AddPolylineToMarker(); + + if (m_pFileBuf != NULL) + { + delete []m_pFileBuf; + m_pFileBuf = NULL; + } + + return bOk; +} + +#if(0) +void ImportHPGL::creatPolylinePainterPath() +{ + if(m_pMarker == NULL){return;} + + QPainterPath painterPath; + QRect rect = m_pMarker->GetRect(); + int minX = rect.left(); + int minY = rect.top(); + int maxY = rect.bottom(); + + int nLineCount = m_pMarker->m_listPolyline.size(); + // m_polyTextPath = QPainterPath(); + for(int i = 0; i < nLineCount; i++) + { + CRPPolyline polyLine = m_pMarker->m_listPolyline.at(i); + int type = polyLine.m_nDrawingType; + // if(polyLine.m_nDrawingType == 3)//文字 + // { + // CRPText text = polyLine.m_text; + // } + + int nPointCount = polyLine.m_listPoint.size(); + for(int j = 0; j < nPointCount; j++) + { + double x = (polyLine.m_listPoint.at(j).x() - minX)/(double)M_IDPMM*MMPIXELY; + double y = ((0 - (polyLine.m_listPoint.at(j).y() - minY))+(maxY-minY))/(double)M_IDPMM*MMPIXELY; + QPointF point(x,y); + + if(j == 0) + { + painterPath.moveTo(point); + } + else + { + painterPath.lineTo(point); + } + } + } + + m_polylinePainterPath = painterPath; +} +#endif + +//读取一个非空格、非回车、非换行的字符 +//输入参数: +// pFile 切割数据文件 +//输出参数: +// *pChar 读取的字符 +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功取得一个字符 +// false 失败 +bool ImportHPGL::GetChar(char *pChar) +{ + char c; + uint nCount; + bool bOk; + bOk=true; + + nCount = ReadChar(&c); + while ((nCount == 1) && ((c == ' ') || (c == 0x0A) || (c == 0x0D))) + { + nCount = ReadChar(&c); + } + + if (bOk && (nCount == 0)) + { + bOk=false; + } + + if (nCount == 1) + { + *pChar=c; + bOk=true; + } + + return bOk; +} + +uint ImportHPGL::ReadChar(char* lpBuf) +{ + uint nCount = 1; + + if (m_nCharCount < m_nFileLength) + { + *lpBuf = m_pFileBuf[m_nCharCount]; + m_nCharCount = m_nCharCount + 1; + nCount = 1; + } + else + { + nCount = 0; + } + + return nCount; +} + +//判断下一个非空格、非回车、非换行的字符是不是',' +//输入参数: +// pFile 切割数据文件 +//输出参数: +// bEndOfFile =true 已到文件尾 +//返回值: +// true 下一个非空格、非回车、非换行的字符是',', 并且已将','从文件中读出 +// false 下一个非空格、非回车、非换行的字符不是',', 并且该字符没有从文件中读出 +bool ImportHPGL::NextCharIsComma() +{ + char cCh1; + bool bNextCharIsStart; + + bNextCharIsStart=false; + + if (GetChar(&cCh1)) + { + if (cCh1 == ',') + { + bNextCharIsStart=true; + } + else + { + m_nCharCount = m_nCharCount - 1; + } + } + + return bNextCharIsStart; +} + +//取一个整数 +//输入参数: +// pFile 切割数据文件 +//输出参数: +// iValue 取得的整数 +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功取得一个整数iValue +// false 失败 +bool ImportHPGL::GetIntegerData(int &iValue) +{ + QString string1; + char c; + bool bOk,bNum; + + bNum=false; + + bOk=GetChar(&c); + if (bOk && (c == '-')) + { + string1=string1 + c; + bOk=GetChar(&c); + } + while (bOk) + { + if (('0' <= c) && (c <= '9')) + { + string1=string1 + c; + bNum=true; + } + else + { + m_nCharCount = m_nCharCount - 1; + break; + } + + bOk=GetChar(&c); + } + + if (!bOk) + { + if (m_nCharCount == m_nFileLength) + bOk=true; + } + if (!bNum) + bOk=false; + + if (bOk) + iValue=string1.toInt(); + + return bOk; +} + +//取一个双精度浮点数 +//输入参数: +// pFile 切割数据文件 +//输出参数: +// dValue 取得的双精度浮点数 +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功取得一个双精度浮点数dValue +// false 失败 +bool ImportHPGL::GetDoubleData(double &dValue) +{ + QString string1; + char c; + bool bOk,bNum; + + bNum=false; + + bOk=GetChar(&c); + if (bOk && (c == '-')) + { + string1=string1 + c; + bOk=GetChar(&c); + } + while (bOk) + { + if ((('0' <= c) && (c <= '9')) || c == '.') + { + string1=string1 + c; + bNum=true; + } + else + { + m_nCharCount = m_nCharCount - 1; + break; + } + + bOk=GetChar(&c); + } + + if (!bOk) + { + if (m_nCharCount == m_nFileLength) + bOk=true; + } + + if (!bNum) + bOk=false; + + if (bOk) + dValue=string1.toDouble(); + + return bOk; +} + +//取坐标值 +//输入参数: +// pFile 切割数据文件 +//输出参数: +// ptPoint 坐标 +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功 +// false 失败 +bool ImportHPGL::GetCoordinate(QPoint &ptPoint) +{ + bool bOk; + int iX,iY; + double x,y; + QString strInfo; + + ptPoint=m_ptCurrentPos; + //bOk=GetIntegerData(x); + bOk=GetDoubleData(x);//为了兼容Gemini文件,Gemini坐标不是整数,是小数 + if (bOk) + { + iX=(double)(x+m_nLength) * m_dScale * m_dScaleX; + ptPoint.setX(iX); + } + + if (bOk) + { + bOk=SearchChar(',' ,strInfo); + if (bOk) + { + //bOk=GetIntegerData(y); + bOk=GetDoubleData(y);//为了兼容Gemini文件,Gemini坐标不是整数,是小数 + if (bOk) + { + iY=(double)y * m_dScale * m_dScaleY; + ptPoint.setY(iY); + } + + } + } + + return bOk; +} + +//获得线的类型 +//输入参数: +// pFile 切割数据文件 +//输出参数: +// lineType 线型 +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功 +// false 失败 +bool ImportHPGL::GetLineType(LineType &lineType) +{ + bool bOk; + int nLineType, nPatternLength, nMode; + QString strInfo; + lineType = m_lineType; + bOk=GetIntegerData(nLineType); + if (bOk) + { + lineType.bDefault = false; + lineType.nLinetype = nLineType; + bOk=SearchChar( ',' ,strInfo); + if (bOk) + { + bOk=GetIntegerData(nPatternLength); + if (bOk) + { + lineType.nPatternLength = nPatternLength; + } + + bOk=SearchChar( ';' ,strInfo); + if (bOk) + { + bOk=GetIntegerData(nMode); + if (bOk) + { + lineType.nMode = nMode; + } + } + else + { + lineType.nMode = 0; + } + } + else + { + lineType.nPatternLength = 4; + } + } + else + { + lineType.bDefault = true; + } + + return bOk; +} + +//查找一个指定的字符 +//输入参数: +// pFile 切割数据文件 +// cFind 指定的字符 +//输出参数: +// bEndOfFile =true 已到文件尾 +// strInfo 从开始位置到指定字符之前的内容(不包括最后的指定字符) +//返回值: +// true 成功取得一个字符 +// false 失败 +bool ImportHPGL::SearchChar(char cFind,QString &strInfo) +{ + char c; + uint nCount; + bool bOk; + + bOk=true; + strInfo.clear(); + + + nCount = ReadChar(&c); + while ((nCount == 1) && (c != cFind)) + { + strInfo = strInfo + c; + nCount = ReadChar(&c); + } + + + if (bOk && (nCount == 0)) + { + bOk=false; + } + + if (nCount == 1) + { + bOk=true; + } + + return bOk; +} + +//将文件的读取位置移到下一个英文字母(26个英文字母) +//输入参数: +// pFile 切割数据文件 +//输出参数: +// bEndOfFile =true 已到文件尾 +//返回值: +// true 成功将文件的读取位置移到下一个英文字母 +// false 失败 +bool ImportHPGL::MoveToNextEnglishChar() +{ + char c; + uint nCount; + bool bOk, bFind; + + bOk=true; + + bFind = false; + nCount = ReadChar(&c); + while ((nCount == 1) && (!bFind)) + { + if ((('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z'))) + { + m_nCharCount = m_nCharCount - 1; + bFind = true; + } + else + { + nCount = ReadChar(&c); + } + } + + return bOk; +} + +//将m_listXY加入到m_pMarker中,并将m_listXY清空 +void ImportHPGL::AddPolylineToMarker() +{ + //长度<0.2mm为钻孔 + CRPPolyline RPPolyline1; + QPoint pt1,pt2; + CDrill drill; + bool bIsdirll = false; + + if (m_listXY.size() >= 2) + { + if (m_listXY.size() == 2 && m_iPenNo == 3) + { + pt1 = m_listXY.at(0); + pt2 = m_listXY.at(1); + if (((pt1.x() - pt2.x())*(pt1.x() - pt2.x())+(pt1.y() - pt2.y())*(pt1.y() - pt2.y()))<=64) + { + bIsdirll = true; + } + } + if (bIsdirll) + { + drill.m_pt = pt1; + drill.m_nDrillType = 0; + drill.m_nAngle = 0; + RPPolyline1.m_nDrawingType = 5; + RPPolyline1.m_drill = drill; + RPPolyline1.m_nPenNo = drill.m_nDrillType; + } + else + { + RPPolyline1.m_nPenNo = m_iPenNo; + RPPolyline1.m_bPgEnd = m_bPage; + RPPolyline1.m_lineType = m_lineType; + RPPolyline1.m_listPoint.clear(); + RPPolyline1.m_listPoint.append(m_listXY); + } + m_pMarker->m_listPolyline.append(RPPolyline1); + } + else + { + if (m_iPenNo == 20 && m_listXY.size() > 0) + { + drill.m_pt = m_listXY.at(0); + drill.m_nDrillType = 0; + drill.m_nAngle = 0; + RPPolyline1.m_nDrawingType = 5; + RPPolyline1.m_drill = drill; + RPPolyline1.m_nPenNo = drill.m_nDrillType; + m_pMarker->m_listPolyline.append(RPPolyline1); + } + } + m_listXY.clear(); +} + +void ImportHPGL::AddPoint2listXY(QPoint ptPoint) +{ + if ((m_listXY.size() == 0) && (m_ptCurrentPos != ptPoint)) + { + m_listXY.append(m_ptCurrentPos); + } + + m_listXY.append(ptPoint); +} + +void ImportHPGL::AddTextPointToLine(bool bUp,QPoint ptPoint) +{ + if (bUp) + { + AddPolylineToMarker(); + m_ptCurrentPos = ptPoint; + m_bPenUp = true; + } + else + { + AddPoint2listXY(ptPoint); + m_ptCurrentPos = ptPoint; + m_bPenUp = false; + } +} + +QPoint ImportHPGL::GetTextOrigin(QPoint pt,QString strText) +{ + int nLen; + double dTextAngle; + double dLength; + int iX; + int iY; + nLen = strText.size(); + dTextAngle = m_dTextAngle/180.0*PI ; + switch(m_nLableOrigin) + { + case 1: + iX=pt.x()-(m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(m_dTextHeight)*qCos(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 2: + iX=pt.x()-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(0.5*m_dTextHeight)*qCos(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 4: + iX=pt.x()-(m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(m_dTextHeight)*qCos(dTextAngle); + iX=iX-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 5: + iX=pt.x()-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(0.5*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 6: + iX=pt.x()-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=pt.y()-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 7: + iX=pt.x()-(m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(m_dTextHeight)*qCos(dTextAngle); + iX=iX-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 8: + iX=pt.x()-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(0.5*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 9: + iX=pt.x()-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=pt.y()-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 11: + dTextAngle=qAtan2(0.25*m_dTextHeight,0.25*m_dTextWidth)+m_dTextAngle; + dTextAngle=dTextAngle/180.0*PI ; + dLength=qSqrt((0.25*m_dTextHeight)*(0.25*m_dTextHeight)+(0.25*m_dTextWidth)*(0.25*m_dTextWidth)); + iX=pt.x()+dLength*qCos(dTextAngle); + iY=pt.y()+dLength*qSin(dTextAngle); + dTextAngle=m_dTextAngle/180.0*PI; + iX=iX-(m_dTextHeight)*qSin(dTextAngle); + iY=iY+(m_dTextHeight)*qCos(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 12: + iX=pt.x()+(0.25*m_dTextWidth)*qCos(dTextAngle); + iY=pt.y()+(0.25*m_dTextWidth)*qSin(dTextAngle); + iX=iX-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=iY+(0.5*m_dTextHeight)*qCos(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 13: + dTextAngle=qAtan2(0.25*m_dTextHeight,0.25*m_dTextWidth)-m_dTextAngle; + dTextAngle=dTextAngle/180.0*PI; + dLength=qSqrt((0.25*m_dTextHeight)*(0.25*m_dTextHeight)+(0.25*m_dTextWidth)*(0.25*m_dTextWidth)); + iX=pt.x()+dLength*qCos(dTextAngle); + iY=pt.y()-dLength*qSin(dTextAngle); + dTextAngle=m_dTextAngle/180.0*PI; + pt.setX(iX); + pt.setY(iY); + break; + case 14: + iX=pt.x()-(1.25*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(1.25*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 15: + iX=pt.x()-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(0.5*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 16: + iX=pt.x()+(0.25*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()-(0.25*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(0.5*nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(0.5*nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 17: + dTextAngle=qAtan2(0.25*m_dTextHeight,0.25*m_dTextWidth)-m_dTextAngle; + dTextAngle=dTextAngle/180.0*PI; + dLength=qSqrt((0.25*m_dTextHeight)*(0.25*m_dTextHeight)+(0.25*m_dTextWidth)*(0.25*m_dTextWidth)); + iX=pt.x()-dLength*qCos(dTextAngle); + iY=pt.y()+dLength*qSin(dTextAngle); + dTextAngle=m_dTextAngle/180.0*PI; + iX=iX-(m_dTextHeight)*qSin(dTextAngle); + iY=iY+(m_dTextHeight)*qCos(dTextAngle); + iX=iX-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 18: + iX=pt.x()-(0.25*m_dTextWidth)*qCos(dTextAngle); + iY=pt.y()-(0.25*m_dTextWidth)*qSin(dTextAngle); + iX=iX-(0.5*m_dTextHeight)*qSin(dTextAngle); + iY=pt.y()+(0.5*m_dTextHeight)*qCos(dTextAngle); + iX=iX-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + case 19: + dTextAngle=qAtan2(0.25*m_dTextHeight,0.25*m_dTextWidth)+m_dTextAngle; + dTextAngle=dTextAngle/180.0*PI; + dLength=sqrt((0.25*m_dTextHeight)*(0.25*m_dTextHeight)+(0.25*m_dTextWidth)*(0.25*m_dTextWidth)); + iX=pt.x()-dLength*qCos(dTextAngle); + iY=pt.y()-dLength*qSin(dTextAngle); + dTextAngle=m_dTextAngle/180.0*PI; + iX=iX-(nLen*m_dTextWidth)*qCos(dTextAngle); + iY=iY-(nLen*m_dTextWidth)*qSin(dTextAngle); + pt.setX(iX); + pt.setY(iY); + break; + } + return pt; +} + +double ImportHPGL::GetTextAngle(double dX,double dY) +{ + double dAngle = 0; + + if ((dX == 0) && (dY > 0)) + { + dAngle = 90; + } + else if ((dX == 0) && (dY < 0)) + { + dAngle = -90; + } + else if ((dX > 0) && (dY == 0)) + { + dAngle = 0; + } + else if ((dX < 0) && (dY == 0)) + { + dAngle = 180; + } + else if ((dX!=0) && (dY!=0)) + { + dAngle=qAtan2(dY,dX)*180/PI; + } + + double tmp = (dAngle - (int)dAngle); + if(qAbs((int)(tmp*10)) >= 5) + { + double angle = dAngle < 0 ? dAngle += -1 : dAngle+=1; + dAngle = angle; + } + dAngle = (int)dAngle; + + return dAngle; +} + +void ImportHPGL::SetScale() +{ + double dScaleX,dScaleY; + switch(m_sc.nType) + { + case 0://异步 + m_dScaleX=(double)(m_ptP2.x()-m_ptP1.x())/(m_sc.dXMax-m_sc.dXMin); + m_dScaleY=(double)(m_ptP2.y()-m_ptP1.y())/(m_sc.dYMax-m_sc.dYMin); + m_ptOrigin.setX(m_ptP1.x()-m_sc.dXMin*m_dScaleX); + m_ptOrigin.setY(m_ptP1.y()-m_sc.dYMin*m_dScaleY); + break; + case 1://同步 + dScaleX=(double)(m_ptP2.x()-m_ptP1.x())/(m_sc.dXMax-m_sc.dXMin); + dScaleY=(double)(m_ptP2.y()-m_ptP1.y())/(m_sc.dYMax-m_sc.dYMin); + if(dScaleX>dScaleY) //x>y + { + m_dScaleX=dScaleY; + m_dScaleY=dScaleY; + m_ptOrigin.setY(m_ptP1.y()); + m_ptOrigin.setX(((m_ptP2.x()-m_ptP1.x())-(m_sc.dXMax-m_sc.dXMin)*dScaleY)*m_sc.dLeft/100.0); + } + else //x= 22) + { + char cFileBuf[23]; + file.read(&cFileBuf[0],22); + if((cFileBuf[0] == 0x66) && (cFileBuf[1] == 0x53) &&(strncmp(&cFileBuf[3],"Richpeace plot file",19) == 0)) + { + file.close(); + return true; + } + else + { + file.close(); + return false; + } + } + return false; +} + +int ImportHPGL::BitMapDtat(QString strFileName, QString strSecretFile) +{ + int i,j,k,m,n,nRemainChar; + char cFileBuf[1025]; + char cSecretBuf[256]; + char errRe; + QFile file(strFileName); + int nLength; + BOOL bError = FALSE; + + m=j=0; + nRemainChar = 0; + errRe=0; + QFile hFile(strSecretFile); + + if (!hFile.open(QIODevice::WriteOnly|QIODevice::Truncate)) + { + qDebug()<<"strSecretFile open false1"; + return 0; + } + + if(!file.open(QIODevice::ReadOnly)) + { + qDebug()<<"strSecretFile open false1"; + return 0; + } + + nLength = file.size(); + file.read(&cFileBuf[0],22); + i = 22; + + for(;i 0) + { + n = 252 - nRemainChar + 2; + if (j > nRemainChar) + { + m = 254; + j -= nRemainChar; + i += nRemainChar; + } + else + { + m = n + j; + i += j; + j = 0; + } + if ((n < m) && ((nRemainChar & 0x01) != 0)) + { + nRemainChar -= (m - n); + cFileBuf[k++] = cSecretBuf[n++] ^ cSecretBuf[1]; + } + else + nRemainChar -= (m - n); + for (;n 0) + { + if (nLength == i) + { + break; + } + if ((nLength - i) < 256) + { + bError = TRUE; + errRe = 1; + break; + } + file.read(cSecretBuf,256); + i += 256; + cSecretBuf[0] ^= cSecretBuf[254]; + cSecretBuf[1] ^= cSecretBuf[255]; + cSecretBuf[0] ^= 0xac; + cSecretBuf[1] ^= 0xe3; + if (j < 252) + { + m = j + 2; + nRemainChar = 252 - j; + j = 0; + i -= nRemainChar; + } + else + { + m = 254; + j -= 252; + nRemainChar = 0; + } + if ((m & 0x01) != 0) + { + m--; + for (n=2;nm_iDPMM / 40; + m_listXY.clear(); + nSecretFileLength = file.size(); + pSecretFileBuf = new unsigned char[nSecretFileLength]; + if(pSecretFileBuf != NULL) + { + file.read((char*)pSecretFileBuf,nSecretFileLength); + } + file.close(); + + while (i < nSecretFileLength) + { + c = pSecretFileBuf[i++]; + switch (c) + { + case DEFCMD_IN://0x8a://IN + break; + case DEFCMD_PG://0x97://PG + m_nLength = m_pMarker->GetRect().right(); + break; + case DEFCMD_SP://0x7c: + { + AddPolylineToMarker(); + unsigned char cTemp; + cTemp = pSecretFileBuf[i++]; + m_iPenNo = cTemp; + } + break; + case DEFCMD_LT://0xe6: + { + c = pSecretFileBuf[i++]; + c ^= 0xce; + if (c != 0) + { + if (c == 1) + c = 3; + else if (c == 2) + c = 1; + else + c = 8; + } + } + break; + case DEFCMD_SI://0x5d: 字体宽×高 + { + cPin = (unsigned char *)&m_dTextWidth; + for(int nCount=7; nCount>=0; nCount--) + { + *(cPin+nCount) = pSecretFileBuf[i++]; + } + m_dTextWidth = m_dTextWidth * 10 * M_IDPMM; + + cPin = (unsigned char *)&m_dTextHeight; + for(int nCount=7; nCount>=0; nCount--) + { + *(cPin+nCount) = pSecretFileBuf[i++]; + } + m_dTextHeight = m_dTextHeight * 10 * M_IDPMM; + } + break; + case DEFCMD_LB://0x4d: + { + AddPolylineToMarker(); + cPin = (unsigned char *)&nParameter; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + m_ptCurrentPos.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + m_ptCurrentPos.setY(pointy); + + strTemp.clear(); + QByteArray tempArr; + tempArr.clear(); + for(int nCount=0; nCounttoUnicode(tempArr); + + m_ptCurrentPos = GetTextOrigin(m_ptCurrentPos,strTemp); + vectorFont.m_dFontHeight = m_dTextHeight; + vectorFont.m_dFontAngle = m_dTextAngle; + vectorFont.TextOutString(m_ptCurrentPos.x(),m_ptCurrentPos.y(),(const char*)strTemp.data(),strTemp.length()); + } + break; + case DEFCMD_DI://0x5B: + { + cPin = (unsigned char *)&m_dTextAngle; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + m_bFontItalic = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&m_iFontSize; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + } + break; + case DEFCMD_FN://0x4B: + { + m_strFontName = ""; + cPin = (unsigned char *)&iFontNameLenth; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + for (int a = 0; a < iFontNameLenth; a++) + { + char chTemp = pSecretFileBuf[i++]; + m_strFontName = m_strFontName + chTemp; + } + } + break; + case DEFCMD_DRILL://0xD2:冲孔 + { + AddPolylineToMarker(); + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + drill.m_pt.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + drill.m_pt.setY(pointy); + + cPin = (unsigned char *)&drill.m_nDrillType; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&drill.m_nAngle; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + RPPolyline.m_nDrawingType = 5; + RPPolyline.m_drill = drill; + RPPolyline.m_nPenNo = drill.m_nDrillType; + m_pMarker->m_listPolyline.append(RPPolyline); + } + break; + case DEFCMD_NOTCH://0xD3:剪口 + { + AddPolylineToMarker(); + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + notch.m_ptStart.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + notch.m_ptStart.setY(pointy); + + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + notch.m_ptEnd.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + notch.m_ptEnd.setY(pointy); + + cPin = (unsigned char *)¬ch.m_nWidth; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)¬ch.m_nNotchType; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + notch.CovertToOutputByOffset(notchOffsetX,notchOffsetY); + RPPolyline.m_nDrawingType = 6; + RPPolyline.m_notch = notch; + RPPolyline.m_nPenNo = notchPenNO; + m_pMarker->m_listPolyline.append(RPPolyline); + } + break; + case DEFCMD_PU://0xb5: + case DEFCMD_LPU://0x5e: + { + AddPolylineToMarker(); + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + ptPoint.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + ptPoint.setY(pointy); + + m_ptCurrentPos = ptPoint; + m_bPenUp = true; + } + break; + case DEFCMD_PD://0x3d: + case DEFCMD_LPD://0x3b: + { + cPin = (unsigned char *)&pointx; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + ptPoint.setX(pointx); + + cPin = (unsigned char *)&pointy; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + ptPoint.setY(pointy); + + AddPoint2listXY(ptPoint); + m_ptCurrentPos = ptPoint; + } + break; + case DEFCMD_NULL://0x00:空指令 + AddPolylineToMarker(); + break; + case DEFCMD_BT://0x9a: + { + AddPolylineToMarker(); + + //位图的左上角在整个图中的X位置 + //位图的左上角在整个图中的Y位置 + //位图的左下角在整个图中的X位置 + //位图的左下角在整个图中的Y位置 + //位图的右上角在整个图中的X位置 + //位图的右上角在整个图中的Y位置 + //位图的右下角在整个图中的X位置 + //位图的右下角在整个图中的Y位置 + for(int nCount=0; nCount<8; nCount++) + { + cPin = (unsigned char *)&nParameter; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + bitPost[nCount] = nParameter; + } + + //为1时则为透明显示; 为0则为非透明显示 + //背景颜色(在透明显示时背景颜色的点将不被显示) + for(int nCount=0; nCount<2; nCount++) + { + cPin = (unsigned char *)&nParameter; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + bitDispStyle[nCount] = nParameter; + } + + //GDI+中BitmapData的Width,单位:像素 + //GDI+中BitmapData的Height,单位:像素 + //GDI+中BitmapData的Stride(每行的字节数) + //GDI+中BitmapData的PixelFormat + for(int nCount=0; nCount<4; nCount++) + { + cPin = (unsigned char *)&nParameter; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + bitGDIInfo[nCount] = nParameter; + } + + //int压缩后位图数据大小(字节数) V1.01开始有此数据 + cPin = (unsigned char *)&nParameter; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + bitmapInfo.m_ptPostLU.setX(bitPost[0]); + bitmapInfo.m_ptPostLU.setY(bitPost[1]); + bitmapInfo.m_ptPostLD.setX(bitPost[2]); + bitmapInfo.m_ptPostLD.setY(bitPost[3]); + bitmapInfo.m_ptPostRU.setX(bitPost[4]); + bitmapInfo.m_ptPostRU.setY(bitPost[5]); + bitmapInfo.m_ptPostRD.setX(bitPost[6]); + bitmapInfo.m_ptPostRD.setY(bitPost[7]); + + bitmapInfo.m_ptAbPostLU.setX(bitPost[0] + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLU.setY(bitPost[1] + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostLD.setX(bitPost[2] + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLD.setY(bitPost[3] + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRU.setX(bitPost[4] + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRU.setY(bitPost[5] + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRD.setX(bitPost[6] + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRD.setY(bitPost[7] + m_ptOrigin.y()); + + bitmapInfo.m_iTransparent = bitDispStyle[0]; + bitmapInfo.m_iBKColor = bitDispStyle[1]; + + bitmapInfo.m_iWidth = bitGDIInfo[0]; + bitmapInfo.m_iHeight = bitGDIInfo[1]; + bitmapInfo.m_iStride = bitGDIInfo[2]; + bitmapInfo.m_iPixelFormat = bitGDIInfo[3]; + + bitmapInfo.m_iBytes = nParameter; + + QByteArray unBmpArr; + unBmpArr.clear(); + pBmpData = new BYTE[bitmapInfo.m_iBytes]; + for(int nCount=0; nCountapplicationDirPath()); + QString zipPath = apppath.path(); + QString zipFile = stePathName + "bfile.zip"; + QFile file(zipFile); + if (!file.open(QIODevice::WriteOnly)) + { + qDebug()<<"zipFile open false"; + return false; + } + file.write(unBmpArr); + file.close(); + + QZipReader reader(zipFile); + if(!reader.exists()) + { + return false; + } + + reader.extractAll(zipFile); + //QVector list = reader.fileInfoList(); + QZipReader::FileInfo fileInfo = reader.entryInfoAt(0);//文件夹名称 + pUnCompressData = reader.fileData(fileInfo.filePath); + reader.close(); + + // bitmapInfo.m_pBitmap = plotBitmap.Create1BPPBitmap(bitmapInfo.m_iTransparent,bitmapInfo.m_iBKColor,bitmapInfo.m_iWidth,bitmapInfo.m_iHeight, + // bitmapInfo.m_iStride,bitmapInfo.m_iPixelFormat, pUnCompressData.data()); + + bitmapInfo.m_pBitmap = plotBitmap.Create1BPPBitmap(bitmapInfo.m_iWidth,bitmapInfo.m_iHeight, (unsigned char*)pUnCompressData.data()); + QString reStr = zipPath + apppath.separator() + fileInfo.filePath; + QFile::remove(reStr); + QFile::remove(zipFile); + delete pBmpData; + + RPPolyline.m_nDrawingType = 1; + RPPolyline.m_bitmapInfo = bitmapInfo; + m_pMarker->m_listPolyline.append(RPPolyline); + } + break; + case DEFCMD_CODE://0xE7: + { + AddPolylineToMarker(); + cPin = (unsigned char *)&code.m_nLX; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nLY; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nSizeX; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nSizeY; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nAngle; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nType; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + cPin = (unsigned char *)&code.m_nCount; + *(cPin+3) = pSecretFileBuf[i++]; + *(cPin+2) = pSecretFileBuf[i++]; + *(cPin+1) = pSecretFileBuf[i++]; + *cPin = pSecretFileBuf[i++]; + + code.m_strCode.clear(); + + QByteArray codeArr; + codeArr.clear(); + for(int nCount=0; nCounttoUnicode(codeArr); + + if (code.m_nType == 0) + { + } + else if (code.m_nType == 1) + { + int nVesion = GetQRVesion(code.m_nCount); + pCode = QRcode_encodeString(code.m_strCode.toStdString().c_str(),nVesion,QR_ECLEVEL_L,QR_MODE_8,1); + if (pCode != NULL) + { + int scale = 1; + + int qrCode_Width = pCode->width > 0 ? pCode->width : 1; + int width = scale * qrCode_Width; + int height = scale * qrCode_Width; + + QImage image(width, height, QImage::Format_ARGB32); + + QPainter painter(&image); + QColor background(Qt::white); + painter.setBrush(background); + painter.setPen(Qt::NoPen); + painter.drawRect(0, 0, width, height); + QColor foreground(Qt::black); + painter.setBrush(foreground); + for(int y = 0; y < qrCode_Width; ++y) + { + for(int x = 0; x < qrCode_Width; ++x) + { + unsigned char character = pCode->data[y * qrCode_Width + x]; + if(character & 0x01) + { + QRect rect(x * scale, y * scale, scale, scale); + painter.drawRects(&rect, 1); + } + } + } + + QBitmap qrPixmap = QBitmap::fromImage(image); + //qrPixmap.save("D:\\1.bmp"); + bitmapInfo.m_pBitmap = qrPixmap; + + if (code.m_nSizeY <= code.m_nSizeX) + { + nPixelsDot = (int)((double)code.m_nSizeY / (double)pCode->width + 0.5); + } + else + { + nPixelsDot = (int)((double)code.m_nSizeX / (double)pCode->width + 0.5); + } + + int nStride = WIDTHBYTES(pCode->width * nPixelsDot); + + bitmapInfo.m_ptPostLU.setX(code.m_nLX); + bitmapInfo.m_ptPostLU.setY(code.m_nLY); + bitmapInfo.m_ptPostLD.setX(code.m_nLX); + bitmapInfo.m_ptPostLD.setY(code.m_nLY - code.m_nSizeY); + bitmapInfo.m_ptPostRU.setX(code.m_nLX + code.m_nSizeX); + bitmapInfo.m_ptPostRU.setY(code.m_nLY); + bitmapInfo.m_ptPostRD.setX(code.m_nLX + code.m_nSizeX); + bitmapInfo.m_ptPostRD.setY(code.m_nLY - code.m_nSizeY); + + dSin = sin(CONST_PI/180.0*code.m_nAngle/100.0); + dCos = cos(CONST_PI/180.0*code.m_nAngle/100.0); + + PointRotate(bitmapInfo.m_ptPostLU,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostLD,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostRU,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostRD,bitmapInfo.m_ptPostLU,dSin,dCos); + + bitmapInfo.m_ptAbPostLU.setX(bitmapInfo.m_ptPostLU.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLU.setY(bitmapInfo.m_ptPostLU.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostLD.setX(bitmapInfo.m_ptPostLD.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLD.setY(bitmapInfo.m_ptPostLD.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRU.setX(bitmapInfo.m_ptPostRU.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRU.setY(bitmapInfo.m_ptPostRU.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRD.setX(bitmapInfo.m_ptPostRD.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRD.setY(bitmapInfo.m_ptPostRD.y() + m_ptOrigin.y()); + + bitmapInfo.m_iTransparent = 0; + bitmapInfo.m_iBKColor = qRgb(255,255,255); + + bitmapInfo.m_iWidth = pCode->width; + bitmapInfo.m_iHeight = pCode->width; + bitmapInfo.m_iStride = nStride; + bitmapInfo.m_iPixelFormat = PixelFormat1bppIndexed; + + bitmapInfo.m_iBytes = pCode->width*nStride; + + RPPolyline.m_nDrawingType = 1; + RPPolyline.m_bitmapInfo = bitmapInfo; + m_pMarker->m_listPolyline.append(RPPolyline); + + QRcode_free(pCode); + } + +#if(0) + if (code.m_nSizeY <= code.m_nSizeX) + { + nPixelsDot = (int)((double)code.m_nSizeY / (double)pCode->width + 0.5); + } + else + { + nPixelsDot = (int)((double)code.m_nSizeX / (double)pCode->width + 0.5); + } + + int nStride = WIDTHBYTES(pCode->width * nPixelsDot); + + BYTE* pData = new BYTE[pCode->width*nPixelsDot*nStride]; + + for (int y = 0; y < pCode->width; y++) + { + for (int x = 0; x < pCode->width; x++) + { + int nByte = x / 8; + int nBit = x % 8; + + if ((pCode->data[y*pCode->width + x] & 0x01)) + { + //SetUncharBit(pData[y*nStride+nByte],7-nBit,0); + for (nIndexRow = 0; nIndexRow < nPixelsDot; nIndexRow++) + { + for (nIndexCol = 0; nIndexCol < nPixelsDot; nIndexCol++) + { + nByte = (x * nPixelsDot + nIndexCol) / 8; + nBit = (x * nPixelsDot + nIndexCol) % 8; + plotBitmap.SetUncharBit(pData[(y*nPixelsDot +nIndexRow)*nStride + nByte], 7 - nBit, 0); + } + } + } + else + { + //SetUncharBit(pData[y*nStride+nByte],7-nBit,1); + for (nIndexRow = 0; nIndexRow < nPixelsDot; nIndexRow++) + { + for (nIndexCol = 0; nIndexCol < nPixelsDot; nIndexCol++) + { + nByte = (x * nPixelsDot + nIndexCol) / 8; + nBit = (x * nPixelsDot + nIndexCol) % 8; + plotBitmap.SetUncharBit(pData[(y * nPixelsDot + nIndexRow)*nStride + nByte], 7 - nBit, 1); + } + } + } + } + } + + bitmapInfo.m_ptPostLU.setX(code.m_nLX); + bitmapInfo.m_ptPostLU.setY(code.m_nLY); + bitmapInfo.m_ptPostLD.setX(code.m_nLX); + bitmapInfo.m_ptPostLD.setY(code.m_nLY - code.m_nSizeY); + bitmapInfo.m_ptPostRU.setX(code.m_nLX + code.m_nSizeX); + bitmapInfo.m_ptPostRU.setY(code.m_nLY); + bitmapInfo.m_ptPostRD.setX(code.m_nLX + code.m_nSizeX); + bitmapInfo.m_ptPostRD.setY(code.m_nLY - code.m_nSizeY); + + dSin = sin(CONST_PI/180.0*code.m_nAngle/100.0); + dCos = cos(CONST_PI/180.0*code.m_nAngle/100.0); + + PointRotate(bitmapInfo.m_ptPostLU,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostLD,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostRU,bitmapInfo.m_ptPostLU,dSin,dCos); + PointRotate(bitmapInfo.m_ptPostRD,bitmapInfo.m_ptPostLU,dSin,dCos); + + bitmapInfo.m_ptAbPostLU.setX(bitmapInfo.m_ptPostLU.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLU.setY(bitmapInfo.m_ptPostLU.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostLD.setX(bitmapInfo.m_ptPostLD.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostLD.setY(bitmapInfo.m_ptPostLD.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRU.setX(bitmapInfo.m_ptPostRU.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRU.setY(bitmapInfo.m_ptPostRU.y() + m_ptOrigin.y()); + bitmapInfo.m_ptAbPostRD.setX(bitmapInfo.m_ptPostRD.x() + m_ptOrigin.x() + m_nLength); + bitmapInfo.m_ptAbPostRD.setY(bitmapInfo.m_ptPostRD.y() + m_ptOrigin.y()); + + bitmapInfo.m_iTransparent = 0; + bitmapInfo.m_iBKColor = qRgb(255,255,255); + + bitmapInfo.m_iWidth = pCode->width; + bitmapInfo.m_iHeight = pCode->width; + bitmapInfo.m_iStride = nStride; + bitmapInfo.m_iPixelFormat = PixelFormat1bppIndexed; + + bitmapInfo.m_iBytes = pCode->width*nStride; + + // bitmapInfo.m_pBitmap = plotBitmap.Create1BPPBitmap(bitmapInfo.m_iTransparent,bitmapInfo.m_iBKColor,bitmapInfo.m_iWidth*nPixelsDot,bitmapInfo.m_iHeight*nPixelsDot, + // bitmapInfo.m_iStride,bitmapInfo.m_iPixelFormat, (char*)pData); + + bitmapInfo.m_pBitmap = plotBitmap.Create1BPPBitmap(bitmapInfo.m_iWidth*nPixelsDot,bitmapInfo.m_iHeight*nPixelsDot,pData); + + RPPolyline.m_nDrawingType = 1; + RPPolyline.m_bitmapInfo = bitmapInfo; + m_pMarker->m_listPolyline.append(RPPolyline);//*/ + + /*code.m_pBitmap = Create1BPPBitmap(0,RGB(255,255,255),pCode->width,pCode->width,nStride,PixelFormat1bppIndexed,pData); + WritreBMP("D:\\345.bmp", pCode->width, pCode->width, nStride, PixelFormat1bppIndexed, pData); + RPPolyline.m_nDrawingType = 4; + RPPolyline.m_code = code; + m_pMarker->m_listPolyline.AddTail(RPPolyline);*/ + + QRcode_free(pCode); + delete []pData; + } +#endif + } + } + break; + default: + qDebug()<GetRect().right(); + //qDebug()<< "length:" << m_nLength; + //qDebug()<< "line count:" << m_pMarker->m_listPolyline.size(); + m_bPage = false; + break; + default: + bOk = MoveToNextEnglishChar(); + break; + } + } + + bOk=true; + return bOk; +} + +bool ImportHPGL::L_Code() +{ + char cCh1; + bool bOk; + QString strText; + VectorFont vectorFont; + connect(&vectorFont, SIGNAL(siLineTo(bool,QPoint)), this, SLOT(AddTextPointToLine(bool,QPoint))); + connect(&vectorFont, SIGNAL(siMoveTo(bool,QPoint)), this, SLOT(AddTextPointToLine(bool,QPoint))); + + CRPPolyline crppolylineTemp; + + bOk=GetChar(&cCh1); + if (bOk) + { + switch (cCh1) + { + case 'T': + case 't': + AddPolylineToMarker(); + GetLineType(m_lineType); + bOk = MoveToNextEnglishChar(); + break; + case 'B': + case 'b': + AddPolylineToMarker(); + bOk = SearchChar(m_chTerminator,strText); + m_ptCurrentPos = GetTextOrigin(m_ptCurrentPos,strText); + + crppolylineTemp.m_nDrawingType = 3; + crppolylineTemp.m_text.m_strText = strText; + crppolylineTemp.m_text.m_ptTextPos = m_ptCurrentPos; + crppolylineTemp.m_text.m_dTextAngle = m_dTextAngle; + crppolylineTemp.m_text.m_nHeight = m_dTextHeight; + crppolylineTemp.m_text.m_nWidth = m_dTextWidth; + crppolylineTemp.m_text.m_ptPostLU = m_ptCurrentPos; + crppolylineTemp.m_text.m_ptPostLD = QPoint(m_ptCurrentPos.x(),m_ptCurrentPos.y()+m_dTextHeight); + crppolylineTemp.m_text.m_ptPostRU = QPoint(m_ptCurrentPos.x()+m_dTextWidth*strText.length(),m_ptCurrentPos.y()); + crppolylineTemp.m_text.m_ptPostRD = QPoint(m_ptCurrentPos.x()+m_dTextWidth*strText.length(),m_ptCurrentPos.y()+m_dTextHeight); + + //用线段方法绘制 +#ifdef Q_OS_WIN + vectorFont.m_dFontHeight = m_dTextHeight; + vectorFont.m_dFontAngle = m_dTextAngle; + vectorFont.TextOutString(m_ptCurrentPos.x(),m_ptCurrentPos.y(),strText.toStdString().c_str(),strText.size()); +#endif + + //qDebug()<m_listPolyline.append(crppolylineTemp);//用文本方法绘制 + + break; + case 'O': + case 'o': + bOk=GetIntegerData(m_nLableOrigin); + break; + default: + bOk = MoveToNextEnglishChar(); + break; + } + } + + return bOk; +} + + +bool ImportHPGL::D_Code() +{ + char cCh1; + bool bOk; + QString strInfo; + + bOk=GetChar(&cCh1); + if (bOk) { + switch (cCh1) { + case 'F': + case 'f': + break; + case 'I': + case 'i': + double dX,dY; + + bOk = GetDoubleData(dX); + if (bOk) + { + bOk = SearchChar(',' ,strInfo); + bOk = GetDoubleData(dY); + } + else + { + dX = 1; + dY = 0; + } + m_dTextAngle = GetTextAngle(dX,dY); + bOk = MoveToNextEnglishChar(); + break; + case 'T': + case 't': + char chTerminator; + int nTerminatorMode; + bOk = GetChar(&chTerminator); + if (bOk) + { + m_chTerminator = chTerminator; + bOk = GetIntegerData(nTerminatorMode); + if (bOk) + { + m_nTerminatorMode = nTerminatorMode; + } + } + bOk = MoveToNextEnglishChar(); + break; + default: + bOk = MoveToNextEnglishChar(); + break; + } + } + + return bOk; +} + +bool ImportHPGL::Write(QString strPathName,Marker *pMarker) +{ + QFile *writeFile = new QFile(strPathName); + writeFile->open(QIODevice::ReadWrite | QFile::Truncate); + // 如果文件没有被占用可以打开 + // 创建stream + QTextStream txtOutput(writeFile); + + QString strHPGL = "IN;DF;SP0;PU0,0;"; + //int nLength = 0; + int i,j; + int iLineCount,iPointCount; + + QString strTemp; + int nOldPenNo = 0; + + bool bSetLT = false; + + iLineCount = pMarker->m_listPolyline.size(); + for (i = 0; i < iLineCount; i++) + { + CRPPolyline polyLine = pMarker->m_listPolyline.at(i); + + if (polyLine.m_lineType.bDefault == false) + { + bSetLT = true; + strTemp = QString("LT%1,%2,%3;").arg(polyLine.m_lineType.nLinetype).arg(polyLine.m_lineType.nPatternLength).arg(1); + } + else + { + if (bSetLT) + strTemp = "LT;"; + } + strHPGL = strHPGL + strTemp; + + if (polyLine.m_nDrawingType == 0) + { + iPointCount = polyLine.m_listPoint.size(); + //选择画笔 1为笔绘 3为半透切割 其它为切割 + if (nOldPenNo != polyLine.m_nPenNo) + { + if (polyLine.m_nPenNo == 1) + { + strTemp = QString("SP%1;").arg(polyLine.m_nPenNo); + nOldPenNo = polyLine.m_nPenNo; + } + else if (polyLine.m_nPenNo == 3) + { + strTemp = QString("SP%1;").arg(polyLine.m_nPenNo); + nOldPenNo = polyLine.m_nPenNo; + } + else + { + strTemp = QString("SP%1;").arg(polyLine.m_nPenNo); + nOldPenNo = polyLine.m_nPenNo; + } + strHPGL = strHPGL + strTemp; + } + + + for (j = 0; j < iPointCount; j++) + { + + QPoint pt = polyLine.m_listPoint.at(j); + + if (j == 0) + { + strTemp = QString("PU%1,%2;").arg(pt.x()).arg(pt.y()); + + } + else if(j == 1) + { + if (j + 1 == iPointCount) + { + strTemp = QString("PD%1,%2;").arg(pt.x()).arg(pt.y()); + + } + else + { + strTemp = QString("PD%1,%2,").arg(pt.x()).arg(pt.y()); + + } + } + else + { + if (j + 1 == iPointCount) + { + + strTemp = QString("%1,%2;").arg(pt.x()).arg(pt.y()); + } + else + { + strTemp = QString("%1,%2,").arg(pt.x()).arg(pt.y()); + + } + } + strHPGL = strHPGL + strTemp; + } + } + else if (polyLine.m_nDrawingType == 5) + { + strTemp = "SP20;"; + strHPGL = strHPGL + strTemp; + strTemp = QString("PU%1,%2;").arg(polyLine.m_drill.m_pt.x()).arg(polyLine.m_drill.m_pt.y()); + strHPGL = strHPGL + strTemp; + strTemp = QString("PD%1,%2;").arg(polyLine.m_drill.m_pt.x()).arg(polyLine.m_drill.m_pt.y()); + strHPGL = strHPGL + strTemp; + nOldPenNo = 20; + } + + // 在stream追加数据,并换行 + txtOutput << strHPGL << endl; + strHPGL = ""; + + } + strHPGL = strHPGL + "SP0;"; + //nLength = strHPGL.size(); + + // 在stream追加数据,并换行 + txtOutput << strHPGL << endl; + strHPGL = ""; + writeFile->close(); + return true; +} + +#if(0) +QPainterPath ImportHPGL::GetPolylinePainterPath() +{ + return m_polylinePainterPath; +} +#endif + +#if(0) +int ImportHPGL::CreatePreviewImage(QString saveName,QImage *pImg, int saveflag) +{ + QImage * pImage = NULL; + int width, height; + width = height = 0; + + if (pImg == NULL) + { + width = (m_maxX - m_minX) / M_IDPMM + 2*PREVIEW_SIDE; + height = (m_maxY - m_minY) / M_IDPMM+ 2*PREVIEW_SIDE; + pImage = new QImage(width, height, QImage::Format_ARGB32); // + } + else + { + pImage = pImg; + } + + width = pImage->width(); + height = pImage->height(); + if (width < PREVIEW_SIDE*2 || height < PREVIEW_SIDE*2) + { + if (pImage != NULL) + { + delete pImage; + } + return -1; + } + + QPainter painter(pImage); + QColor backcolor(255, 255, 255, 255); + QColor pencolor(0, 0, 0, 255); + + // 背景 + QPen pen; + pen.setWidth(1); + pen.setColor(backcolor); + painter.setPen(pen); + painter.setBrush(backcolor); + painter.drawRect(0, 0, width, height); + + // 图形显示区域 + int dpminx = PREVIEW_SIDE; + int dpmaxx = width - PREVIEW_SIDE; + int dpminy = PREVIEW_SIDE; + int dpmaxy = height - PREVIEW_SIDE; + + // 计算缩放系数 + double factor, temp; + factor = (double)(abs(m_maxX - m_minX)) / (dpmaxx - dpminx); // 按x计算的缩放系数 + temp = (double)(abs(m_maxY - m_minY)) / (dpmaxy - dpminy); // 按轮廓计算,最小能够放下重复次数个图形 + if (temp >= factor) // 使用较大的缩放系数 + { + factor = temp; + } + + // 计算显示参数,按照图形的实际位置显示(数据坐标零点对应图形中心) + int dpx = (int)((dpminx+dpmaxx)/2 - ((m_maxX+m_minX)/factor)/2); + int dpy = (int)((dpminy+dpmaxy)/2 - ((m_maxY+m_minY)/factor)/2); + + int curx, cury, prex, prey; + curx = cury = prex = prey = 0; + + curx = dpx; + cury = (height) - dpy; + + pen.setColor(pencolor); + painter.setPen(pen); + + int nLineCount = m_pMarker->m_listPolyline.size(); + for(int i = 0; i < nLineCount; i++) + { + CRPPolyline polyLine = m_pMarker->m_listPolyline.at(i); + int nPointCount = polyLine.m_listPoint.size(); + for(int j = 0; j < nPointCount; j++) + { + prex = curx; + prey = cury; + + curx = polyLine.m_listPoint.at(j).x() / factor+ dpx; + cury = height - (polyLine.m_listPoint.at(j).y() / factor + dpy); + + if(j == 0) + { + continue; + } + + painter.drawLine(prex, prey, curx, cury); + } + } + + // 保存成文件 + if (saveflag != 0) + { + saveName += ".preview.bmp"; + pImage->save(saveName, "bmp"); + } + + if (pImage != NULL) + { + pImage = NULL; + delete pImage; + } + + return 0; +} +#endif diff --git a/datafile/hpgl/importhpgl.h b/datafile/hpgl/importhpgl.h new file mode 100644 index 0000000..2fb6b28 --- /dev/null +++ b/datafile/hpgl/importhpgl.h @@ -0,0 +1,268 @@ +#ifndef IMPORTHPGL_H +#define IMPORTHPGL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "marker.h" +#include "plotbitmap.h" +#include "QtGui/private/qzipreader_p.h" +//#include "QtGui/private/qzipwriter_p.h" +#include "datafile/qrencode/qrencode.h" + +#define DEFCMD_IN 0x8A //IN +#define DEFCMD_SP 0x7C //SP +#define DEFCMD_LT 0xE6 //LT 0:PS_SOLID; 1:PS_DASH; 2:PS_DOT; 3:PS_DASHDOT +#define DEFCMD_PG 0x97 //PG +#define DEFCMD_PU 0xB5 //PU 单个PU +#define DEFCMD_PD 0x3D //PD 单个PD +#define DEFCMD_LPU 0x5E //PU 连续PU +#define DEFCMD_LPD 0x3B //PD 连续PD +#define DEFCMD_DI 0x5B //AG 角度 +#define DEFCMD_SI 0x5D //SI 64位双精度浮点 +#define DEFCMD_FN 0x4B //FN 字体名 +#define DEFCMD_LB 0x4D //LB +#define DEFCMD_BT 0x9A //BIT 位图 +#define DEFCMD_CODE 0xE7 //CODE 条形码、二维码 +#define DEFCMD_NULL 0x00 //NUll 空指令 +#define DEFCMD_DRILL 0xD2 //DRILL 冲孔 +#define DEFCMD_NOTCH 0xD3 //NOTCH 剪口 + +#define M_IDPMM 40.0 +#define MMPIXELY (600/25.4) + +#define PREVIEW_SIDE (10) +#define PREVIEW_WIDTH (240) +#define PREVIEW_HEIGHT (240) + +#define WIDTHBYTES(bits) (((bits)+31)/32*4) + +#define PixelFormatIndexed 0x00010000 // Indexes into a palette +#define PixelFormatGDI 0x00020000 // Is a GDI-supported format +#define PixelFormat1bppIndexed (1 | ( 1 << 8) | PixelFormatIndexed | PixelFormatGDI) + +struct SC +{ + double dXMin; + double dXMax; + double dYMin; + double dYMax; + int nType; + double dLeft; + double dBottom; +}; + +class ImportHPGL : public QObject +{ + Q_OBJECT +public: + explicit ImportHPGL(QObject *parent = 0); + virtual ~ImportHPGL(); + +signals: + +public slots: + +private: + //获得QR二维码版本 + //输入参数:nCount 字符个数 + //返回参数:QR二维码版本 + int GetQRVesion(int nCount); + + //样点旋转 + //输入参数: + // ptPoint被旋转点,ptPointO旋转原点,dSinBeta,dCosBeta逆时针旋转角度的正余弦 + //输出参数: + // ptPoint旋转后的值 + void PointRotate(QPoint &ptPoint,QPoint ptPointO,double dSinBeta,double dCosBeta); + +protected: + + //分析S指令 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // bEndOfFile =true 已到文件尾 + //返回值: + // true 正确的G指令 + // false 不正确的G指令 + bool S_Code(); + bool I_Code(); + bool P_Code(); + bool PU_Code(); + bool PD_Code(); + bool L_Code(); + bool D_Code(); + bool SC_Code(); + bool C_Code(); + + //读取一个字符 + //输出参数: + // *pChar 读取的字符 + //返回值: + // 1 成功取得一个字符 + // 0 失败 + uint ReadChar(char* lpBuf); + + //读取一个非空格、非回车、非换行的字符 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // *pChar 读取的字符 + //返回值: + // true 成功取得一个字符 + // false 失败 + bool GetChar(char *pChar); + //判断下一个非空格、非回车、非换行的字符是不是',' + //输入参数: + // pFile 切割数据文件 + //返回值: + // true 下一个非空格、非回车、非换行的字符是',', 并且已将','从文件中读出 + // false 下一个非空格、非回车、非换行的字符不是',', 并且该字符没有从文件中读出 + bool NextCharIsComma(); + + //取一个双精度浮点数 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // dValue 取得的双精度浮点数 + //返回值: + // true 成功取得一个双精度浮点数dValue + // false 失败 + bool GetDoubleData(double &dValue); + + //取一个整数 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // iValue 取得的整数 + //返回值: + // true 成功取得一个整数iValue + // false 失败 + bool GetIntegerData(int &iValue); + + //取坐标值 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // ptPoint 坐标 + //返回值: + // true 成功 + // false 失败 + bool GetCoordinate(QPoint &ptPoint); + + //获得线的类型 + //输入参数: + // pFile 切割数据文件 + //输出参数: + // lineType 线型 + //返回值: + // true 成功 + // false 失败 + bool GetLineType(LineType &lineType); + + //查找一个指定的字符 + //输入参数: + // pFile 切割数据文件 + // cFind 指定的字符 + //输出参数: + // strInfo 从开始位置到指定字符之前的内容(不包括最后的指定字符) + //返回值: + // true 成功取得一个字符 + // false 失败 + bool SearchChar(char cFind,QString &strInfo); + + //将文件的读取位置移到下一个英文字母(26个英文字母) + //输入参数: + // pFile 切割数据文件 + //输出参数: + // *pChar 读取的字符 + //返回值: + // true 成功将文件的读取位置移到下一个英文字母 + // false 失败 + bool MoveToNextEnglishChar(); + + //将m_listXY加入到m_pMarker中,并将m_listXY清空 + void AddPolylineToMarker(); + + void AddPoint2listXY(QPoint ptPoint); + + int m_iDPMM; //长度数据单位:m_iDPMM(每毫米点) + int m_iPenNo; //当前的笔号 + QPoint m_ptCurrentPos; //笔的当前位置,单位:(1/CMarker::m_iDPMM)毫米 + LineType m_lineType;//当前线型 + bool m_bPenUp;//当前刀具的状态 true:刀具状态为抬起 false:刀具状态为落下 + bool m_bPage;//是否识别到PG指令 + + Marker *m_pMarker; //当前使用的唛架,仅能在读文件时使用 + double m_dScale; //读入文件时将切割数据文件的单位转换成内部数据单位时的比例 + QPen m_penPen;//笔绘画笔 + QPen m_cutPen;//切割画笔 + QPen m_halfCutPen;//半透切割画笔 + + QList m_listXY; //还没有确定抬落刀的坐标 + //QPainterPath m_polylinePainterPath;//绘图路径-线段 + + unsigned char m_chTerminator;//标志终结符,除了NULL LF ESC及;十进制分别为0,5,27,59;外的所有字符,默认为ETX 十进制3 + int m_nTerminatorMode;//模式0:打印1:不打印 默认值为1 + + double m_dTextHeight;//字的高度 单位cm + double m_dTextWidth;//字的宽度 单位cm + int m_nLableOrigin;//字符串相对于原点位置 + double m_dTextAngle;//指定每行文本输出时相对于设备x轴的角度,其单位为1/10度 + QPoint m_ptP1;//解析IP指令中的坐标点 + QPoint m_ptP2;//解析IP指令中的坐标点 + SC m_sc;//解析SC指令 + double m_dScaleX;//通过 IP和SC指令算出的缩放比例 + double m_dScaleY;//通过 IP和SC指令算出的缩放比例 + QPoint m_ptOrigin;//通过 IP和SC指令算出的原点 + int m_nLength;//用于PG分页,记录累计长度 + char* m_pFileBuf;//存放从文件中读取的全部字符 + int m_nCharCount;//已经读取的字符个数 + int m_nFileLength;//文件长度 + QString m_workPath; + + bool m_bFontItalic; //文字斜体 + int m_iFontSize; //字体榜数 + QString m_strFontName;//字体名称 + +public: + //输入参数: + // pFile 需要读入的RS274D文件 + // pMarker 解析到的数据保存到此唛架 + //返回值: + // true 读入文件成功 + // false 读入文件失败 + bool Read(QString strPathName,Marker *pMarker); + bool Write(QString strPathName,Marker *pMarker); + //void creatPolylinePainterPath();//获得文件图形的范围 + //QPainterPath GetPolylinePainterPath(); + //int CreatePreviewImage(QString saveName,QImage * pImg = NULL, int saveflag = 0); + + //初始化参数,读取参数前,需将参数值重置,避免造成参数值读取错误 + void IniPara(); + + QPoint GetTextOrigin(QPoint pt,QString strText); + double GetTextAngle(double dX,double dY); + void SetScale(); + bool IsSecretFile(QString strPatnName); + int BitMapDtat(QString strFileName,QString strSecretFile); + bool ReadSecretFile(QString stePathName,Marker *pMarker); // 打开位图文件 + +private slots: + //输入参数: + // bUp 刀的状态,true:抬起状态 false:落下状态 + // ptPoint 矢量字体中点阵中的一个坐标 + void AddTextPointToLine(bool bUp,QPoint ptPoint); +}; + +#endif // IMPORTHPGL_H diff --git a/datafile/hpgl/marker.cpp b/datafile/hpgl/marker.cpp new file mode 100644 index 0000000..6d222bd --- /dev/null +++ b/datafile/hpgl/marker.cpp @@ -0,0 +1,261 @@ +#include "marker.h" + +Marker::Marker(QObject *parent) : + QObject(parent) +{ + m_iDPMM = 40; + m_listPolyline.clear(); + m_nProducts = 0; + m_nActualMatchRegions = 0; + m_nMatchRegions = 0; + m_strProductCode = ""; +} +Marker::~Marker() +{ +} + +Marker::Marker(const Marker &a): QObject() +{ + m_iDPMM = a.m_iDPMM; + m_listPolyline.clear(); + m_listPolyline.append(a.m_listPolyline); + m_nProducts = a.m_nProducts; + m_nActualMatchRegions = a.m_nActualMatchRegions; + m_nMatchRegions = a.m_nMatchRegions; + m_strProductCode = a.m_strProductCode; +} + +Marker Marker::operator=(const Marker &a) +{ + m_iDPMM = a.m_iDPMM; + m_listPolyline.clear(); + m_listPolyline.append(a.m_listPolyline); + m_nProducts = a.m_nProducts; + m_nActualMatchRegions = a.m_nActualMatchRegions; + m_nMatchRegions = a.m_nMatchRegions; + m_strProductCode = a.m_strProductCode; + return *this; +} + +void Marker::Initialize() +{ + m_iDPMM = 40; + m_listPolyline.clear(); + m_nProducts = 0; + m_nActualMatchRegions = 0; + m_nMatchRegions = 0; + m_strProductCode = ""; +} + +QRect Marker::GetRect() +{ + QRect rect; + + CRPPolyline RPPolyline; + rect.setRect(0,0,0,0); + + for(int i = 0; i < m_listPolyline.size(); i++) + { + RPPolyline = m_listPolyline.at(i); + if (RPPolyline.m_nDrawingType == 0) + { + rect |= RectofPolyline(RPPolyline.m_listPoint); + } + else if (RPPolyline.m_nDrawingType == 3) + { + rect |= QRect(RPPolyline.m_text.m_ptPostLU,RPPolyline.m_text.m_ptPostRD); + } + else if (RPPolyline.m_nDrawingType == 1) + { + rect |= QRect(RPPolyline.m_bitmapInfo.m_ptAbPostLU,RPPolyline.m_bitmapInfo.m_ptAbPostRD); + } + } + + return rect; +} + +QRect Marker::RectofPolyline(const QList &listPoint) +{ + if(listPoint.empty()) + { + return QRect(0,0,0,0); + } + int iXMin = INT_MAX; + int iXMax = INT_MIN; + int iYMin = INT_MAX; + int iYMax = INT_MIN; + + int iValueX; + int iValueY; + + int iPointCount = listPoint.size(); + for(int i = 0 ;i < iPointCount; i++) + { + iValueX = listPoint.at(i).x(); + iValueY = listPoint.at(i).y(); + + if( iValueX > iXMax ) + { + iXMax = iValueX; + } + + if(iValueX < iXMin ) + { + iXMin = iValueX; + } + + if( iValueY > iYMax ) + { + iYMax = iValueY; + } + + if(iValueY < iYMin ) + { + iYMin = iValueY; + } + } + + return QRect(QPoint(iXMin,iYMin),QPoint(iXMax,iYMax)); +} + + +double CNotch::angle_2(int startx, int starty, int endx, int endy) +{ + //直线与X轴之间的夹角 X轴向量OE(1,0) + double dAngle = 0; + if((endx == startx) && (endy == starty)) + { + return dAngle; + } + //求直线的向量坐标 + double dX = endx - startx; + double dY = endy - starty; + dAngle = qAcos((dX)/(qSqrt(dX*dX + dY*dY))); + return dAngle; +} + +void CNotch::CovertToOutputByOffset(int nOffSetX, int nOffsetY) +{ + double a = 0; + double b = 0; + double c = 0; + //范围在[0,2pi)之间 + double dAngle = angle_2(m_ptStart.x(),m_ptStart.y(),m_ptEnd.x(),m_ptEnd.y()); + m_nAngle = dAngle*180.0/CONST_PI*100.0 + 0.5; + //double dX = m_ptEnd.x - m_ptStart.x; + //double dY = m_ptEnd.y - m_ptStart.y; + //double dLen = sqrt(dX*dX + dY*dY); + //m_ptCorrect.x = nOffSetY/dLen * dX + m_ptStart.x; + //m_ptCorrect.y = nOffsetY/dLen * dY + m_ptStart.y; + QPoint ptY; + ptY.setX(nOffsetY*cos(dAngle) + m_ptStart.x() + 0.5); + ptY.setY(nOffsetY*sin(dAngle) + m_ptStart.y() + 0.5); + + if (nOffSetX == 0) + { + m_ptCorrect.setX(ptY.x()); + m_ptCorrect.setY(ptY.y()); + return; + } + + int nX = m_ptEnd.x() - m_ptStart.x(); + int nY = m_ptEnd.y() - m_ptStart.y(); + + if (nX == 0) + { + a = 0; + b = 1; + c = -ptY.y(); + } + if (nY == 0) + { + a = 1; + b = 0; + c = -ptY.x(); + } + + double k = double(m_ptStart.x() - m_ptEnd.x())/double(m_ptEnd.y() - m_ptStart.y()); + c = ptY.y() - k*ptY.x(); + a = k; + b = -1; + int nRadius = abs(nOffSetX); + QPoint ptInter1; + QPoint ptInter2; + if (IntOfLineCircle(a,b,c,ptY.x(),ptY.y(),nRadius,ptInter1,ptInter2) == 2) + { + //向量 + int nYv = ptInter1.y() - ptY.y(); + int nXv = ptInter1.x() - ptY.x(); + //判断该点在起点到终点连线的哪一侧?>0 右侧 + if((nXv*nY -nYv*nX)>0) + { + if (nOffSetX > 0)//右侧 + { + m_ptCorrect.setX(ptInter1.x()); + m_ptCorrect.setY(ptInter1.y()); + } + else + { + m_ptCorrect.setX(ptInter2.x()); + m_ptCorrect.setY(ptInter2.y()); + } + + } + else + { + if (nOffSetX < 0)//左侧 + { + m_ptCorrect.setX(ptInter1.x()); + m_ptCorrect.setY(ptInter1.y()); + } + else + { + m_ptCorrect.setX(ptInter2.x()); + m_ptCorrect.setY(ptInter2.y()); + } + } + } +} + +int CNotch::IntOfLineCircle(double a, double b, double c, int xc, int yc, int nR, QPoint &lpptIntersection1, QPoint &lpptIntersection2) +{ + //点:(x0,y0) + //线:Ax+By+C=0 + //①距离=ABS(A*x0+B*y0+C) / SQRT(A*A+B*B) + double dis = 0; + dis = abs(a*xc+b*yc+c)/sqrt(a*a+b*b); + + int rel = 0; + if(dis < nR) + { + rel = 0; + } + else if(dis == nR) + { + rel = 1; + } + else if(dis > nR) + { + double k = -a/b; + double b1 = 2*xc-2*k*(b-yc); + double sval = (b1/100.0)*(b1/100.0)*10000.0-4*a*c; + if(sval < 0) + { + qDebug()< +#include +#include +#include +#include +#include +#include +#include + +#define CONST_PI 3.14159265359 + +struct LineType +{ + //具体参照HPGL英文版手册216页 当LT没有设置值时,线型为实线 + bool bDefault;//LT是否设置值 + int nLinetype;//线型 取值为-8~8 ,99 =0 实线 =1 虚线 + int nPatternLength;//图案长度 缺省为P1、P2距离的4% + int nMode;//0相对模式 缺省值 解释为P1、P2距离的百分比 1绝对模式,以毫米解释图案长度 +}; + + +class CBitmapInfo +{ +public: + //原始读取的的坐标 + QPoint m_ptPostLU; //位图的左上角在整个图中的XY位置 + QPoint m_ptPostLD; //位图的左下角在整个图中的XY位置 + QPoint m_ptPostRU; //位图的右上角在整个图中的XY位置 + QPoint m_ptPostRD; //位图的右下角在整个图中的XY位置 + + //换算后的坐标 + QPoint m_ptAbPostLU; //位图的左上角在整个图中的XY位置 + QPoint m_ptAbPostLD; //位图的左下角在整个图中的XY位置 + QPoint m_ptAbPostRU; //位图的右上角在整个图中的XY位置 + QPoint m_ptAbPostRD; //位图的右下角在整个图中的XY位置 + + int m_iTransparent;//为1时则为透明显示; 为0则为非透明显示 + int m_iBKColor;//背景颜色(在透明显示时背景颜色的点将不被显示) + + int m_iWidth;// GDI+中BitmapData的Width,单位:像素 + int m_iHeight;//GDI+中BitmapData的Height,单位:像素 + int m_iStride;//GDI+中BitmapData的Stride(每行的字节数) + int m_iPixelFormat;//GDI+中BitmapData的PixelFormat + + int m_iBytes;//int压缩后位图数据大小(字节数) + QBitmap m_pBitmap;//位图数据(压缩后的位图数据) + + CBitmapInfo() + { + m_ptPostLU = QPoint(0,0); + m_ptPostLD = QPoint(0,0); + m_ptPostRU = QPoint(0,0); + m_ptPostRD = QPoint(0,0); + m_ptAbPostLU = QPoint(0,0); + m_ptAbPostLD = QPoint(0,0); + m_ptAbPostRU = QPoint(0,0); + m_ptAbPostRD = QPoint(0,0); + m_iTransparent = 0; + m_iBKColor = 0; + m_iWidth = 0; + m_iHeight = 0; + m_iStride = 0; + m_iPixelFormat = 1; + m_iBytes = 0; + //m_pBitmap = NULL; + + } + ~CBitmapInfo() {} + CBitmapInfo operator=(const CBitmapInfo &a) + { + m_ptPostLU = a.m_ptPostLU; + m_ptPostLD = a.m_ptPostLD; + m_ptPostRU = a.m_ptPostRU; + m_ptPostRD = a.m_ptPostRD; + m_ptAbPostLU = a.m_ptAbPostLU; + m_ptAbPostLD = a.m_ptAbPostLD; + m_ptAbPostRU = a.m_ptAbPostRU; + m_ptAbPostRD = a.m_ptAbPostRD; + m_iTransparent = a.m_iTransparent; + m_iBKColor = a.m_iBKColor; + m_iWidth = a.m_iWidth; + m_iHeight = a.m_iHeight; + m_iStride = a.m_iStride; + m_iPixelFormat = a.m_iPixelFormat; + m_iBytes = a.m_iBytes; + m_pBitmap = a.m_pBitmap; + return *this; + } +}; + +class CRPArc +{ +public: + QPoint m_ptCenter; + int m_nRadius; + bool m_bCircle;//是圆还是圆弧1:圆 0 :圆弧 + QPoint m_ptStart;//圆弧起始点 + QPoint m_ptEnd;//圆弧结束点 + + CRPArc() + { + m_bCircle = true; + } + ~CRPArc() {} + CRPArc(CRPArc &a) + { + m_ptCenter = a.m_ptCenter; + m_nRadius = a.m_nRadius; + m_bCircle = a.m_bCircle; + m_ptStart = a.m_ptStart; + m_ptEnd = a.m_ptEnd; + } + CRPArc operator=(const CRPArc &a) + { + m_ptCenter = a.m_ptCenter; + m_nRadius = a.m_nRadius; + m_bCircle = a.m_bCircle; + m_ptStart = a.m_ptStart; + m_ptEnd = a.m_ptEnd; + return *this; + } +}; + +class CRPText +{ +public: + QString m_strText;//字符串 + QString m_strFontName;//字体名称 + QPoint m_ptTextPos;//文字起点坐标 + double m_dTextAngle;//文字角度 + int m_nHeight;//文字高度 + int m_nWidth;//文字宽度 + int m_nWeight;//加粗 + bool m_bItalic;//斜体 + + //文字坐标 + QPoint m_ptPostLU; //文字的左上角在整个图中的XY位置 + QPoint m_ptPostLD; //文字的左下角在整个图中的XY位置 + QPoint m_ptPostRU; //文字的右上角在整个图中的XY位置 + QPoint m_ptPostRD; //文字的右下角在整个图中的XY位置 + + + CRPText() + { + m_strText = ""; + m_strFontName = ""; + m_ptTextPos = QPoint(0,0); + m_dTextAngle = 0; + m_nHeight = 0; + m_nWidth = 0; + m_nWeight = 0; + m_bItalic = false; + m_ptPostLU = QPoint(0,0); + m_ptPostLD = QPoint(0,0); + m_ptPostRU = QPoint(0,0); + m_ptPostRD = QPoint(0,0); + } + ~CRPText() {} + CRPText(CRPText &a) + { + m_strText = a.m_strText; + m_strFontName = a.m_strFontName; + m_ptTextPos = a.m_ptTextPos; + m_dTextAngle = a.m_dTextAngle; + m_nHeight = a.m_nHeight; + m_nWidth = a.m_nWidth; + m_nWeight = a.m_nWeight; + m_bItalic = a.m_bItalic; + m_ptPostLU = a.m_ptPostLU; + m_ptPostLD = a.m_ptPostLD; + m_ptPostRU = a.m_ptPostRU; + m_ptPostRD = a.m_ptPostRD; + } + CRPText operator=( const CRPText &a) + { + m_strText = a.m_strText; + m_strFontName = a.m_strFontName; + m_ptTextPos = a.m_ptTextPos; + m_dTextAngle = a.m_dTextAngle; + m_nHeight = a.m_nHeight; + m_nWidth = a.m_nWidth; + m_nWeight = a.m_nWeight; + m_bItalic = a.m_bItalic; + m_ptPostLU = a.m_ptPostLU; + m_ptPostLD = a.m_ptPostLD; + m_ptPostRU = a.m_ptPostRU; + m_ptPostRD = a.m_ptPostRD; + return *this; + } +}; + +class CCode +{ +public: + int m_nLX;//左上角X位置 + int m_nLY;//左上角Y位置 + int m_nSizeX;//X方向大小 + int m_nSizeY;//Y方向大小 + int m_nAngle;//角度(逆时针方向为正),单位:0.01度 + int m_nType;//类型(0:条形码,1:二维码) + int m_nCount;//字符串个数(字符串的字节数) + QString m_strCode;//字符串 + QBitmap *m_pBitmap;//生成的位图数据 + + CCode() + { + m_nLX = 0; + m_nLY = 0; + m_nSizeX = 0; + m_nSizeY = 0; + m_nAngle = 0; + m_nType = 0; + m_nCount = 0; + m_strCode = ""; + } + ~CCode() {} + CCode(CCode &a) + { + m_nLX = a.m_nLX; + m_nLY = a.m_nLY; + m_nSizeX = a.m_nSizeX; + m_nSizeY = a.m_nSizeY; + m_nAngle = a.m_nAngle; + m_nType = a.m_nType; + m_nCount = a.m_nCount; + m_strCode = a.m_strCode; + m_pBitmap = a.m_pBitmap; + } + CCode operator=(const CCode &a) + { + m_nLX = a.m_nLX; + m_nLY = a.m_nLY; + m_nSizeX = a.m_nSizeX; + m_nSizeY = a.m_nSizeY; + m_nAngle = a.m_nAngle; + m_nType = a.m_nType; + m_nCount = a.m_nCount; + m_strCode = a.m_strCode; + m_pBitmap = a.m_pBitmap; + return *this; + } +}; + +class CNotch +{ +public: + QPoint m_ptStart;//剪口起点 + QPoint m_ptEnd;//剪口终点 + int m_nWidth;//剪口宽度 + int m_nNotchType;//剪口类型 + QPoint m_ptCorrect;//通过根据刀的X、Y偏移计算得出的实际落刀位置 + int m_nAngle;//根据交口起点和终点计算得出的角度(逆时针方向为正),单位:0.01度 + double angle_2(int startx,int starty,int endx,int endy); + + CNotch() + { + m_ptStart = QPoint(0,0); + m_ptEnd = QPoint(0,0); + m_nWidth = 0;; + m_nNotchType = 0; + m_ptCorrect = QPoint(0,0); + m_nAngle = 0; + } + ~CNotch() {} + CNotch(CNotch &a) + { + m_ptStart = a.m_ptStart; + m_ptEnd = a.m_ptEnd; + m_nWidth = a.m_nWidth; + m_nNotchType = a.m_nNotchType; + m_ptCorrect = a.m_ptCorrect; + m_nAngle = a.m_nAngle; + } + CNotch operator=(const CNotch &a) + { + m_ptStart = a.m_ptStart; + m_ptEnd = a.m_ptEnd; + m_nWidth = a.m_nWidth; + m_nNotchType = a.m_nNotchType; + m_ptCorrect = a.m_ptCorrect; + m_nAngle = a.m_nAngle; + return *this; + } + void CovertToOutputByOffset(int nOffSetX,int nOffsetY); + int IntOfLineCircle(double a,double b,double c,int xc,int yc,int nR,QPoint &lpptIntersection1,QPoint &lpptIntersection2); + +}; + +class CDrill +{ +public: + QPoint m_pt;//冲孔的位置 + int m_nDrillType;//冲孔类型 + int m_nAngle;//冲孔的角度(逆时针方向为正),单位:0.01度 + + CDrill() + { + m_pt = QPoint(0,0); + m_nDrillType = 0;; + m_nAngle = 0; + } + ~CDrill() {} + CDrill(CDrill &a) + { + m_pt = a.m_pt; + m_nDrillType = a.m_nDrillType; + m_nAngle = a.m_nAngle; + } + CDrill operator=(const CDrill &a) + { + m_pt = a.m_pt; + m_nDrillType = a.m_nDrillType; + m_nAngle = a.m_nAngle; + return *this; + } +}; + +class CRPPolyline +{ +public: + int m_nDrawingType;//0:直线 1:位图 2:圆 3:文字 4:条形码、二维码 5:钻孔 6:剪口 + int m_nID;//标识切割线切割顺序 从0开始 + int m_nPenNo; + bool m_bSelect;//是否处于选中状态,true:选中状态 false:未选中状态 + bool m_bPgEnd;//标识该切割线是该页的最后一条线 + int m_nComType;//补偿类型 0 无补偿 1向右(内)补偿 2向左(外)补偿 + + CBitmapInfo m_bitmapInfo; + CRPArc m_circle; + CRPText m_text; + CCode m_code; + CDrill m_drill; + CNotch m_notch; + + LineType m_lineType; + QList m_listPoint; + + CRPPolyline() + { + m_nDrawingType = 0; + m_nID = 0; + m_nPenNo = 0; + m_bSelect = false; + m_bPgEnd = false; + m_lineType.bDefault = true; + m_listPoint.clear(); + m_nComType = 0; + } + ~CRPPolyline() {} + CRPPolyline(const CRPPolyline &a) + { + m_nDrawingType = a.m_nDrawingType; + m_nID = a.m_nID; + m_nPenNo = a.m_nPenNo; + m_bSelect = a.m_bSelect; + m_bPgEnd = a.m_bPgEnd; + m_lineType = a.m_lineType; + m_listPoint.clear(); + m_listPoint.append(a.m_listPoint); + m_text = a.m_text; + m_nComType = a.m_nComType; + m_circle = a.m_circle; + m_text = a.m_text; + m_code = a.m_code; + m_notch = a.m_notch; + m_drill = a.m_drill; + m_bitmapInfo = a.m_bitmapInfo; + } + CRPPolyline operator=( const CRPPolyline &a) + { + m_nDrawingType = a.m_nDrawingType; + m_nID = a.m_nID; + m_nPenNo = a.m_nPenNo; + m_bSelect = a.m_bSelect; + m_bPgEnd = a.m_bPgEnd; + m_lineType = a.m_lineType; + m_listPoint.clear(); + m_listPoint.append(a.m_listPoint); + m_text = a.m_text; + m_nComType = a.m_nComType; + m_circle = a.m_circle; + m_text = a.m_text; + m_code = a.m_code; + m_notch = a.m_notch; + m_drill = a.m_drill; + m_bitmapInfo = a.m_bitmapInfo; + return *this; + } +}; + +class Marker : public QObject +{ + Q_OBJECT +public: + explicit Marker(QObject *parent = 0); + virtual ~Marker(); + Marker(const Marker &a); + Marker operator=(const Marker &a); + void Initialize(); + QRect GetRect(); + QRect RectofPolyline(const QList &listPoint); + + double m_iDPMM; //长度数据单位:m_iDPMM(每毫米点) + QList m_listPolyline; //切割的点链,单位:1/m_iDPMM mm, X向右为正,Y向上为正 + int m_nProducts; + int m_nActualMatchRegions; + int m_nMatchRegions; + QString m_strProductCode;//产品型号 + + +signals: + +public slots: + +}; + +#endif // MARKER_H diff --git a/datafile/hpgl/plotbitmap.cpp b/datafile/hpgl/plotbitmap.cpp new file mode 100644 index 0000000..ff441ad --- /dev/null +++ b/datafile/hpgl/plotbitmap.cpp @@ -0,0 +1,89 @@ +#include "plotbitmap.h" + +PlotBitmap::PlotBitmap(QObject *parent) : QObject(parent) +{ + +} + +//QBitmap PlotBitmap::Create1BPPBitmap(int bTransparent, int crBkColor, int iWidth, int iHeight, int iStride, int nPixFormat, char *pBmpData) +QBitmap PlotBitmap::Create1BPPBitmap(int iWidth,int iHeight,unsigned char *pBmpData) +{ + if(pBmpData == NULL) + { + qDebug()<<"pBmpData == NULL"; + } + + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(Qt::black)); + + //QImage::Format_RGBA8888 代表彩色图 + QImage image = QImage(pBmpData, iWidth, iHeight, QImage::Format_RGBA8888); + //image.save("D:\\1.png"); + + QBitmap pixmap = QBitmap(iWidth,iHeight); + QPainter *pixPainter = new QPainter(); + pixPainter->begin(&pixmap); + pixPainter->setPen(pen); + pixmap.fill(Qt::white);//用白色填充 + pixPainter->drawImage(0,0,image); + //pixmap.save("D:\\1.bmp"); + pixPainter->end(); + +#if(0)//转灰度图 + QImage gimage = QImage(); + uchar* pImageData1 = NULL,*pImageData2 = NULL; + + pImageData1 = image.bits(); + + gimage = image.convertToFormat(QImage::Format_Indexed8); + + QVector table; + for( int i = 0 ; i < 256 ; ++i ) + { + table.append(qRgb(i,i,i)); + } + + gimage.setColorTable(table); + + for(int i =0; i< gimage.width();i++) + { + for(int j=0; j< gimage.height();j++) + { + QRgb pix_value = gimage.pixel(i,j); + gimage.setPixel(i,j,qGray(pix_value)); + } + + } + + pImageData2 = gimage.bits(); + gimage.save("D:\\1.bmp"); + +#endif + if(pixPainter != NULL) + { + delete pixPainter; + } + return pixmap; +} + +//设置unsigned char中某位的值 +//dat 需要设置的unsigned char +//index 设置位 +//val 设置值0或者1 +void PlotBitmap::SetUncharBit(unsigned char &dat, int index, int val) +{ + unsigned int bitmod = 0x01; + if(index >= 0 && index < 8) + { + bitmod <<= index; + if (val == 0) + { + dat &= ~bitmod; + } + else + { + dat |= bitmod; + } + } +} diff --git a/datafile/hpgl/plotbitmap.h b/datafile/hpgl/plotbitmap.h new file mode 100644 index 0000000..3e861ee --- /dev/null +++ b/datafile/hpgl/plotbitmap.h @@ -0,0 +1,65 @@ +#ifndef PLOTBITMAP_H +#define PLOTBITMAP_H + +#include +#include +#include +#include +#include +//#include + +//BMP文件头(14字节) +typedef struct /**** BMP file header structure ****/ +{ + unsigned short bfType; /* 类型 */ + unsigned int bfSize; /* 整个bmp文件大小 */ + unsigned short bfReserved1; /* Reserved */ + unsigned short bfReserved2; /* ... */ + unsigned int bfOffBits; /* 偏移数,位图文件头+位图信息头+调色板大小 */ +} BmpHeader; + +//位图信息头(40字节) +typedef struct /**** BMP file info structure ****/ +{ + unsigned int biSize; /* Size of info header */ + int biWidth; /* Width of image */ + int biHeight; /* Height of image */ + unsigned short biPlanes; /* Number of color planes */ + unsigned short biBitCount; /* Number of bits per pixel */ + unsigned int biCompression; /* Type of compression to use */ + unsigned int biSizeImage; /* Size of image data */ + int biXPelsPerMeter; /* X pixels per meter */ + int biYPelsPerMeter; /* Y pixels per meter */ + unsigned int biClrUsed; /* Number of colors used */ + unsigned int biClrImportant; /* Number of important colors */ +} BmpInfo; + +class PlotBitmap : public QObject +{ + Q_OBJECT +public: + explicit PlotBitmap(QObject *parent = nullptr); + +public: + //创建单色的位图 + //输入参数: + // bTransparent 透明显示 + // crBkColor 背景颜色(在透明显示时位图中颜色为crBkColor的点将不被显示在纸样上) + // iWidth 位图的宽,单位:像素 + // iHeight 位图的高,单位:像素 + // iStride 位图每行的字节数 + // nPixFormat 位图点的格式(见GDI+中BitmapData类PixelFormat的定义) + // pBmpData 位图数据(保存数据的顺序是从左到右,从上到下) + //返回值: + // NULL 失败 + // 非NULL 新生成的位图指针 + //QBitmap Create1BPPBitmap(int bTransparent,int crBkColor,int iWidth,int iHeight,int iStride,int nPixFormat,char *pBmpData); + QBitmap Create1BPPBitmap(int iWidth,int iHeight,unsigned char *pBmpData); + + void SetUncharBit(unsigned char & dat, int index, int val); +signals: + +public slots: +}; + +#endif // PLOTBITMAP_H diff --git a/datafile/hpgl/typedef.h b/datafile/hpgl/typedef.h new file mode 100644 index 0000000..cf4918e --- /dev/null +++ b/datafile/hpgl/typedef.h @@ -0,0 +1,107 @@ +#ifndef TYPEDEF_H +#define TYPEDEF_H + +//--------------------------------------------------------------- + + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +//--------------------------------------------------------------- + + +#define DATA_VALID 0x55AA + +//--------------------------------------------------------------- + +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef unsigned long int DWORD; + +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned int u32; +typedef char s8; +typedef short int s16; +typedef int s32; + +//--------------------------------------------------------------- + +#define U8_MAX ((u8)255) +#define S8_MAX ((s8)127) +#define S8_MIN ((s8)(-128)) +#define U16_MAX ((u16)65535u) +#define S16_MAX ((s16)32767) +#define S16_MIN ((s16)(-32768)) +#define U32_MAX ((u32)4294967295uL) +#define S32_MAX ((s32)2147483647uL) +#define S32_MIN ((s32)(-2147483648uL)) + +//--------------------------------------------------------------- +#ifndef LOBYTE +#define LOBYTE(w) ((BYTE)(((WORD)(w)) & 0xff)) +#endif + +#ifndef HIBYTE +#define HIBYTE(w) ((BYTE)((((WORD)(w)) >> 8) & 0xff)) +#endif + +#ifndef LOWORD +#define LOWORD(l) ((WORD)(((DWORD)(l)) & 0xffff)) +#endif + +#ifndef HIWORD +#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xffff)) +#endif + +#ifndef MAKEWORD +#define MAKEWORD(a, b) ((WORD)((BYTE)(a)) | (((WORD)((BYTE)(b))) << 8)) +#endif + +#ifndef MAKEDWORD +#define MAKEDWORD(a, b) ((DWORD)((WORD)(a)) | (((DWORD)((WORD)(b))) << 16)) +#endif + +#ifndef LOHFBYTE +#define LOHFBYTE(b) ((BYTE)((b) & 0x0f)) +#endif + +#ifndef HIHFBYTE +#define HIHFBYTE(b) ((BYTE)(((b) >> 4) & 0x0f)) +#endif + +#ifndef MAKEBYTE +#define MAKEBYTE(a, b) ((BYTE)((BYTE)((a) & 0x0f)) | ((BYTE)(((BYTE)((b) & 0x0f)) << 4))) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +//--------------------------------------------------------------- + +#ifndef PI + +#define PI 3.1415926535897932 + +#endif + + + + +#endif // TYPEDEF_H diff --git a/datafile/hpgl/vectorfont.cpp b/datafile/hpgl/vectorfont.cpp new file mode 100644 index 0000000..e9befaf --- /dev/null +++ b/datafile/hpgl/vectorfont.cpp @@ -0,0 +1,918 @@ +#include "vectorfont.h" +#include +#include +#include "main.h" +VectorFont::VectorFont(QObject *parent) : + QObject(parent) +{ + m_iDPMM = 40; + m_pChinese_char = NULL; + m_pEnglish_char = NULL; + m_nChinese_char_count = 0; + m_nEnglish_char_count = 0; + IniVectorFont(); +} + + +VectorFont::~VectorFont() +{ + if(m_pChinese_char != NULL) + { + delete []m_pChinese_char; + m_pChinese_char = NULL; + } + if(m_pEnglish_char != NULL) + { + delete []m_pEnglish_char; + m_pEnglish_char = NULL; + } +} +void VectorFont::IniVectorFont() +{ + + QFile fntFile; + QString strCharFileName; + + BYTE byte[10]; + int nCharCount_C; + int nCharCount_E; + CChinese_char Chinese_char1; + CEnglish_char English_char1; + int nCountChar; + + + QString appPath = QCoreApplication::applicationDirPath(); + QChar separator = QChar('/'); + if(!appPath.contains(separator)) // 判断分隔符 + { + separator = QChar('\\'); + } + m_workPath = appPath + separator; + + + strCharFileName = m_workPath + "english.fnt"; + //qDebug()<< "strCharFileName" << strCharFileName; + fntFile.setFileName(strCharFileName); + + if(!fntFile.open(QIODevice::ReadOnly)) + { + qDebug() <<"english file open failed"; + return; + } + + fntFile.seek(0); + fntFile.read((char*)byte,10); + + m_nInternalLeading_E=(int)((WORD)byte[0] | ((WORD)byte[1] << 8)); + m_nHeight_E=(int)((WORD)byte[2] | ((WORD)byte[3] << 8)); + m_nDescent_E=(int)((WORD)byte[4] | ((WORD)byte[5] << 8)); + nCharCount_E=(int)((DWORD)byte[6] | ((DWORD)byte[7] << 8) | ((DWORD)byte[9] << 16) | ((DWORD)byte[9] << 24)); + //m_aEnglish_char.clear(); + m_pEnglish_char = new CEnglish_char[nCharCount_E]; + m_nEnglish_char_count = nCharCount_E; + fntFile.seek(10); + + nCountChar=nCharCount_E; + while (nCountChar > 0) + { + fntFile.read((char*)byte,10); + + English_char1.m_wCharCode=(WORD)byte[0] | ((WORD)byte[1] << 8); + English_char1.m_wBytes=(WORD)byte[2] | ((WORD)byte[3] << 8); + English_char1.m_wWidth=(WORD)byte[4] | ((WORD)byte[5] << 8); + English_char1.m_dwPosition=(DWORD)byte[6] | ((DWORD)byte[7] << 8) | ((DWORD)byte[9] << 16) | ((DWORD)byte[9] << 24); + + m_pEnglish_char[nCharCount_E-nCountChar] = English_char1; + //m_aEnglish_char.append(English_char1); + + nCountChar--; + } + fntFile.close(); + + strCharFileName = m_workPath + "Hz.fnt"; + //qDebug()<< "strCharFileName" << strCharFileName; + fntFile.setFileName(strCharFileName); + if(!fntFile.open(QIODevice::ReadOnly)) + { + qDebug() <<"chinese file open failed"; + return; + } + fntFile.seek(0); + fntFile.read((char*)byte,8); + + m_nWidth_C=(int)((WORD)byte[0] | ((WORD)byte[1] << 8)); + m_nHeight_C=(int)((WORD)byte[2] | ((WORD)byte[3] << 8)); + nCharCount_C=(int)((DWORD)byte[4] | ((DWORD)byte[5] << 8) | ((DWORD)byte[6] << 16) | ((DWORD)byte[7] << 24)); + + //m_aChinese_char.clear(); + m_pChinese_char = new CChinese_char[nCharCount_C]; + m_nChinese_char_count = nCharCount_C; + + fntFile.seek(8); + nCountChar=nCharCount_C; + while (nCountChar > 0) + { + fntFile.read((char*)byte,8); + + Chinese_char1.m_wCharCode=(WORD)byte[0] | ((WORD)byte[1] << 8); + Chinese_char1.m_wBytes=(WORD)byte[2] | ((WORD)byte[3] << 8); + Chinese_char1.m_dwPosition=(DWORD)byte[4] | ((DWORD)byte[5] << 8) | ((DWORD)byte[6] << 16) | ((DWORD)byte[7] << 24); + + + m_pChinese_char[nCharCount_C-nCountChar] = Chinese_char1; + //m_aChinese_char.append(Chinese_char1); + nCountChar--; + } + fntFile.close(); + + m_dFontAngle = 0; + m_dFontHeight = 0.375 * 10 * m_iDPMM; +} + + +//输入参数: +// ptPointLU 显示字符串的左上角坐标(即TextOut(...)的x,y值) +// pbyData 字符的描述数据 +// wBytes 字符的描述数据个数 +// nLeft,nDown 字符的左下角坐标(即以英汉字库的公共单位及坐标水平绘制字符串时,字符的的左下角坐标) +// nFontScale 字库的长度比例 +void VectorFont::PlotChar(QPoint ptPointLU,BYTE *pbyData,WORD wBytes,int nLeft,int nDown,int nFontScale) +{ + BYTE byByteX,byByteY; + QPoint ptCurrentPos,ptCenter,ptPointS,ptPointE; + QPoint ptPoint1; + WORD wIndex1; + WORD wDirection,wLength; + BOOL bPenUp,bVerTextCommand,bClockwise; + WORD wRadius,wArcS,wSpan; + int nRadius; + double dAngleS,dAngleE,dAngleOffsetS,dAngleOffsetE; + double dx1,dy1,dx2,dy2,dxc,dyc,dr,dD,dH,dBulge; + double dCos,dSin; + double dLToDScale; + int nHeight; + + if (wBytes == 0) return; + + nHeight=(m_nInternalLeading_E + m_nHeight_E) * m_nHeight_E; + //nHeight=(m_nInternalLeading_E + m_nHeight_E) * m_nHeight_C; //之前 + dLToDScale=(double)nHeight / m_dFontHeight; + + m_dRake = m_dFontAngle/180.0*PI; + dCos=cos(m_dRake); + dSin=sin(m_dRake); + + ptCurrentPos=QPoint(nLeft,nDown); + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + MoveTo(ptPoint1); + bVerTextCommand=false; + bPenUp=false; + wIndex1=0; + while (wIndex1 < wBytes) { + switch (pbyData[wIndex1]) { + case 0x0: + wIndex1++; + break; + case 0x1: + wIndex1++; + bPenUp=false; + break; + case 0x2: + wIndex1++; + bPenUp=true; + break; + case 0x3: + wIndex1++; + wIndex1++; + bVerTextCommand=false; + break; + case 0x4: + wIndex1++; + wIndex1++; + bVerTextCommand=false; + break; + case 0x5: + wIndex1++; + bPenUp=true; + break; + case 0x6: + wIndex1++; + bPenUp=true; + break; + case 0x7: + wIndex1++; + wIndex1++; + bPenUp=true; + break; + case 0x8: + if (bVerTextCommand) { + wIndex1=wIndex1+3; + } + else { + wIndex1++; + ptCurrentPos.setX(ptCurrentPos.x() + (char)pbyData[wIndex1] * nFontScale); + wIndex1++; + ptCurrentPos.setY(ptCurrentPos.y() + (char)pbyData[wIndex1] * nFontScale); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + if (bPenUp) + MoveTo(ptPoint1); + else + LineTo(ptPoint1); + + wIndex1++; + } + bVerTextCommand=false; + break; + case 0x9: + if (bVerTextCommand) { + wIndex1++; + byByteX=pbyData[wIndex1]; + wIndex1++; + byByteY=pbyData[wIndex1]; + while ((byByteX != 0) || (byByteY != 0)) { + wIndex1++; + byByteX=pbyData[wIndex1]; + wIndex1++; + byByteY=pbyData[wIndex1]; + } + wIndex1++; + } + else { + wIndex1++; + byByteX=pbyData[wIndex1]; + wIndex1++; + byByteY=pbyData[wIndex1]; + while ((byByteX != 0) || (byByteY != 0)) { + ptCurrentPos.setX(ptCurrentPos.x() + (char)byByteX * nFontScale); + ptCurrentPos.setY(ptCurrentPos.y() + (char)byByteY * nFontScale); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + if (bPenUp) + MoveTo(ptPoint1); + else + LineTo(ptPoint1); + + wIndex1++; + byByteX=pbyData[wIndex1]; + wIndex1++; + byByteY=pbyData[wIndex1]; + } + + wIndex1++; + } + bVerTextCommand=false; + break; + case 0xA: + if (bVerTextCommand) { + wIndex1=wIndex1+3; + } + else { + wIndex1++; + wRadius=(WORD)pbyData[wIndex1]; + wIndex1++; + if (((char)pbyData[wIndex1]) < 0) bClockwise=true; + else bClockwise=false; + wArcS=(WORD)pbyData[wIndex1]; + wArcS=wArcS & 0x70; + wArcS=wArcS >> 4; + wSpan=(WORD)pbyData[wIndex1]; + wSpan=wSpan & 0x7; + + //计算圆心 + ptCenter=ptCurrentPos; + ptCenter.setX(ptCenter.x() - ((double)wRadius * (double)nFontScale * cos((double)wArcS * 45.0 / 180.0 * 3.14159265359))+0.5); + ptCenter.setY(ptCenter.y() - ((double)wRadius * (double)nFontScale * sin((double)wArcS * 45.0 / 180.0 * 3.14159265359))+0.5); + + dAngleS=(double)wArcS * 45.0 / 180.0 * 3.14159265359; + if (bClockwise) dAngleE=dAngleS - (double)wSpan * 45.0 / 180.0 * 3.14159265359; + else dAngleE=dAngleS + (double)wSpan * 45.0 / 180.0 * 3.14159265359; + + if (bClockwise) { + ptPointS.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleE)+0.5); + ptPointS.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleE)+0.5); + ptPointE.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleS)+0.5); + ptPointE.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleS)+0.5); + ptCurrentPos=ptPointS; + } + else { + ptPointS.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleS)+0.5); + ptPointS.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleS)+0.5); + ptPointE.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleE)+0.5); + ptPointE.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleE)+0.5); + ptCurrentPos=ptPointE; + } + + ptCenter=CPToLP(ptCenter,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointS=CPToLP(ptPointS,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointE=CPToLP(ptPointE,nHeight,ptPointLU,dSin,dCos,dLToDScale); + nRadius=(double)wRadius * (double)nFontScale / dLToDScale + 0.5; + Arc(ptCenter.x() - nRadius,ptCenter.y() - nRadius, + ptCenter.x() + nRadius,ptCenter.y() + nRadius, + ptPointS.x(),ptPointS.y(),ptPointE.x(),ptPointE.y()); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + MoveTo(ptPoint1); + + wIndex1++; + } + bVerTextCommand=false; + break; + case 0xB: + if (bVerTextCommand) { + wIndex1=wIndex1+6; + } + else { + wIndex1++; + dAngleOffsetS=(double)((WORD)pbyData[wIndex1]); + wIndex1++; + dAngleOffsetE=(double)((WORD)pbyData[wIndex1]); + wIndex1++; + wRadius=(WORD)pbyData[wIndex1]; + wRadius=wRadius << 8; + wIndex1++; + wRadius=wRadius | (WORD)pbyData[wIndex1]; + wIndex1++; + if (((char)pbyData[wIndex1]) < 0) bClockwise=true; + else bClockwise=false; + wArcS=(WORD)pbyData[wIndex1]; + wArcS=wArcS & 0x70; + wArcS=wArcS >> 4; + wSpan=(WORD)pbyData[wIndex1]; + wSpan=wSpan & 0x7; + + //计算圆心 + ptCenter=ptCurrentPos; + ptCenter.setX(ptCenter.x() - (double)wRadius * (double)nFontScale * cos((double)wArcS * 45.0 / 180.0 * 3.14159265359)+0.5); + ptCenter.setY(ptCenter.y() - (double)wRadius * (double)nFontScale * sin((double)wArcS * 45.0 / 180.0 * 3.14159265359)+0.5); + + dAngleS=(double)wArcS * 45.0; + dAngleS=dAngleOffsetS * 45.0 / 256.0 + dAngleS; + if (bClockwise) dAngleE=-(double)wSpan * 45.0; + else dAngleE=(double)wSpan * 45.0; + dAngleE=dAngleOffsetE * 45.0 / 256.0 + dAngleE; + dAngleE=dAngleOffsetE * 45.0 / 256.0 + dAngleE; + dAngleS=dAngleS / 180.0 * 3.14159265359; + dAngleE=dAngleE / 180.0 * 3.14159265359; + + if (bClockwise) { + ptPointS.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleE)+0.5); + ptPointS.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleE)+0.5); + ptPointE.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleS)+0.5); + ptPointE.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleS)+0.5); + ptCurrentPos=ptPointS; + } + else { + ptPointS.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleS)+0.5); + ptPointS.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleS)+0.5); + ptPointE.setX(ptCenter.x() + (double)wRadius * (double)nFontScale * cos(dAngleE)+0.5); + ptPointE.setY(ptCenter.y() + (double)wRadius * (double)nFontScale * sin(dAngleE)+0.5); + ptCurrentPos=ptPointE; + } + + ptCenter=CPToLP(ptCenter,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointS=CPToLP(ptPointS,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointE=CPToLP(ptPointE,nHeight,ptPointLU,dSin,dCos,dLToDScale); + nRadius=(double)wRadius * (double)nFontScale / dLToDScale + 0.5; + + Arc(ptCenter.x() - nRadius,ptCenter.y() - nRadius, + ptCenter.x() + nRadius,ptCenter.y() + nRadius, + ptPointS.x(),ptPointS.y(),ptPointE.x(),ptPointE.y()); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + MoveTo(ptPoint1); + + wIndex1++; + } + bVerTextCommand=false; + break; + case 0xC: + if (bVerTextCommand) { + wIndex1=wIndex1+4; + } + else { + wIndex1++; + dx1=(double)((char)pbyData[wIndex1]) * (double)nFontScale; + wIndex1++; + dy1=(double)((char)pbyData[wIndex1]) * (double)nFontScale; + wIndex1++; + dBulge=(double)((char)pbyData[wIndex1]); + if (((char)pbyData[wIndex1]) < 0) bClockwise=true; + else bClockwise=false; + + dD=sqrt(dx1*dx1 + dy1*dy1); + dH=fabs(dBulge) * dD / 127.0 / 2.0; + + if (((char)pbyData[wIndex1]) == 0) { + ptCurrentPos.setX(ptCurrentPos.x() + (int)dx1); + ptCurrentPos.setY(ptCurrentPos.y() - (int)dy1); + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + + if (bPenUp) MoveTo(ptPoint1); + else LineTo(ptPoint1); + } + else { + if (bClockwise) { + dx2=-dy1; + dy2=dx1; + } + else { + dx2=dy1; + dy2=-dx1; + } + dx2=dx2 / dD * dH + dx1 / 2.0; + dy2=dy2 / dD * dH + dy1 / 2.0; + + CircleCR(0.0,0.0,dx2,dy2,dx1,dy1,dxc,dyc,dr); + ptCenter.setX(ptCurrentPos.x() + dxc + 0.5); + ptCenter.setY(ptCurrentPos.y() + dyc + 0.5); + + if (bClockwise) + { + ptPointS.setX(ptCurrentPos.x() + dx1 + 0.5); + ptPointS.setY(ptCurrentPos.y() + dy1 + 0.5 ); + ptPointE=ptCurrentPos; + ptCurrentPos=ptPointS; + } + else + { + ptPointS=ptCurrentPos; + ptPointE.setX(ptCurrentPos.x() + dx1 + 0.5); + ptPointE.setY(ptCurrentPos.y() + dy1 + 0.5); + ptCurrentPos=ptPointE; + } + + ptCenter=CPToLP(ptCenter,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointS=CPToLP(ptPointS,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointE=CPToLP(ptPointE,nHeight,ptPointLU,dSin,dCos,dLToDScale); + nRadius=dr / dLToDScale + 0.5; + + Arc(ptCenter.x() - nRadius,ptCenter.y() - nRadius,ptCenter.x() + nRadius,ptCenter.y() + nRadius, + ptPointS.x(),ptPointS.y(),ptPointE.x(),ptPointE.y()); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + MoveTo(ptPoint1); + } + + wIndex1++; + } + bVerTextCommand=false; + break; + case 0xD: + if (bVerTextCommand) { + wIndex1=wIndex1+4; + } + else { + wIndex1++; + while ((pbyData[wIndex1] != 0) || (pbyData[wIndex1+1] != 0)) { + dx1=(double)((char)pbyData[wIndex1]) * (double)nFontScale; + wIndex1++; + dy1=(double)((char)pbyData[wIndex1]) * (double)nFontScale; + wIndex1++; + dBulge=(double)((char)pbyData[wIndex1]); + if (((char)pbyData[wIndex1]) < 0) bClockwise=true; + else bClockwise=false; + + dD=sqrt(dx1*dx1 + dy1*dy1); + dH=fabs(dBulge) * dD / 127.0 / 2.0; + + if (((char)pbyData[wIndex1]) == 0) { + ptCurrentPos.setX(ptCurrentPos.x() + (int)dx1); + ptCurrentPos.setY(ptCurrentPos.y() - (int)dy1); + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + + if (bPenUp) + MoveTo(ptPoint1); + else + LineTo(ptPoint1); + } + else { + if (bClockwise) { + dx2=-dy1; + dy2=dx1; + } + else { + dx2=dy1; + dy2=-dx1; + } + dx2=dx2 / dD * dH + dx1 / 2.0; + dy2=dy2 / dD * dH + dy1 / 2.0; + + CircleCR(0.0,0.0,dx2,dy2,dx1,dy1,dxc,dyc,dr); + ptCenter.setX(ptCurrentPos.x() + dxc + 0.5); + ptCenter.setY(ptCurrentPos.y() + dyc + 0.5); + + if (bClockwise) + { + ptPointS.setX(ptCurrentPos.x() + dx1 + 0.5); + ptPointS.setY(ptCurrentPos.y() + dy1 + 0.5); + ptPointE=ptCurrentPos; + ptCurrentPos=ptPointS; + } + else + { + ptPointS=ptCurrentPos; + ptPointE.setX(ptCurrentPos.x() + dx1 + 0.5); + ptPointE.setY(ptCurrentPos.y() + dy1 + 0.5); + ptCurrentPos=ptPointE; + } + + ptCenter=CPToLP(ptCenter,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointS=CPToLP(ptPointS,nHeight,ptPointLU,dSin,dCos,dLToDScale); + ptPointE=CPToLP(ptPointE,nHeight,ptPointLU,dSin,dCos,dLToDScale); + nRadius=dr / dLToDScale + 0.5; + + Arc(ptCenter.x() - nRadius,ptCenter.y() - nRadius,ptCenter.x() + nRadius,ptCenter.y() + nRadius, + ptPointS.x(),ptPointS.y(),ptPointE.x(),ptPointE.y()); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + MoveTo(ptPoint1); + } + + wIndex1++; + } + } + bVerTextCommand=false; + break; + case 0xE: + bVerTextCommand=true; + wIndex1++; + break; + default: + if (bVerTextCommand) { + wIndex1++; + } + else { + wDirection=(WORD)(pbyData[wIndex1] % 16); + wLength=(WORD)(pbyData[wIndex1] / 16) * (WORD)nFontScale; + ptCurrentPos=GetNextCoodinate(wDirection,wLength,ptCurrentPos); + + ptPoint1=CPToLP(ptCurrentPos,nHeight,ptPointLU,dSin,dCos,dLToDScale); + if (bPenUp) MoveTo(ptPoint1); + else LineTo(ptPoint1); + + wIndex1++; + } + bVerTextCommand=false; + break; + } + } +} + +QPoint VectorFont::CPToLP(QPoint ptCP,int nHeight,QPoint ptPointLU,double dSin,double dCos,double dScale) +{ + double dx,dy; + QPoint ptPoint1; + + dx=(double)ptCP.x(); + dy=(double)ptCP.y()-(double)nHeight; + ptPoint1.setX(ptPointLU.x() + ((dx*dCos - dy*dSin) / dScale + 0.5)); + ptPoint1.setY(ptPointLU.y() + ((dx*dSin + dy*dCos) / dScale + 0.5)); + + return ptPoint1; +} +//抬笔移动到点(x,y) +void VectorFont::MoveTo(long x, long y) +{ + if(x == 0){} + if(y == 0){} +} + +//抬笔移动到点ptPoint +void VectorFont::MoveTo(QPoint ptPoint) +{ + emit siMoveTo(true,ptPoint); +} + + +//从当前位置画线到点(x,y), +void VectorFont::LineTo(long x, long y) +{ + if(x == 0){} + if(y == 0){} +} + +//从当前位置画线到点ptPoint +void VectorFont::LineTo(QPoint ptPoint) +{ + emit siLineTo(false,ptPoint); +} + +//从(x,y)点开始写字,nCount为字节数 +void VectorFont::TextOutString(int x, int y, const char* lpszString, int nCount) +{ + QString strEnglish,strChinese; + QFile fileEnglish,fileChinese; + BYTE *pbyData; + int nLeft; + BYTE byByte1,byByte2; + WORD wCharCode; + int nIndex1,nIndex2,nIndex3,nIndex4; + bool bEnglishChar; + + strEnglish = m_workPath + "english.fnt"; + strChinese = m_workPath + "Hz.fnt"; + + fileEnglish.setFileName(strEnglish); + if(!fileEnglish.open(QIODevice::ReadOnly)) + { + qDebug() <<"file open failed"; + return; + } + + fileChinese.setFileName(strChinese); + if(!fileChinese.open(QIODevice::ReadOnly)) + { + qDebug() <<"file open failed"; + return; + } + + nLeft=0; + nIndex1=0; + while (nIndex1 < nCount) + { + pbyData=NULL; + byByte1=(BYTE)lpszString[nIndex1]; + if ((byByte1 >= 128) && ((nIndex1+1) < nCount)) + { + bEnglishChar=false; + + nIndex1++; + byByte2=(BYTE)lpszString[nIndex1]; + wCharCode=(((WORD)byByte1) << 8) | (WORD)byByte2; + + nIndex2=0; + nIndex3=m_nChinese_char_count - 1; + if (m_pChinese_char[nIndex2].m_wCharCode == wCharCode) nIndex4=nIndex2; + else if (m_pChinese_char[nIndex3].m_wCharCode == wCharCode) nIndex4=nIndex3; + else nIndex4=(nIndex2 + nIndex3) / 2; + while (((nIndex3 - nIndex2) > 1) && + (m_pChinese_char[nIndex4].m_wCharCode != wCharCode)) + { + if (m_pChinese_char[nIndex4].m_wCharCode > wCharCode) + { + nIndex3=nIndex4; + if (nIndex2 > nIndex3) break; + nIndex4=(nIndex2 + nIndex3) / 2; + } + else + { + nIndex2=nIndex4; + if (nIndex2 > nIndex3) break; + nIndex4=(nIndex2 + nIndex3) / 2; + } + } + + if ((m_pChinese_char[nIndex4].m_wCharCode == wCharCode) && + (m_pChinese_char[nIndex4].m_wBytes > 0)) + { + pbyData=new BYTE[m_pChinese_char[nIndex4].m_wBytes + 1]; + + fileChinese.seek(m_pChinese_char[nIndex4].m_dwPosition); + fileChinese.read((char*)pbyData,m_pChinese_char[nIndex4].m_wBytes); + } + } + else + { + bEnglishChar=true; + wCharCode=(WORD)byByte1; + nIndex2=0; + nIndex3=m_nEnglish_char_count - 1; + if (m_pEnglish_char[nIndex2].m_wCharCode == wCharCode) nIndex4=nIndex2; + else if (m_pEnglish_char[nIndex3].m_wCharCode == wCharCode) nIndex4=nIndex3; + else nIndex4=(nIndex2 + nIndex3) / 2; + while (((nIndex3 - nIndex2) > 1) && + (m_pEnglish_char[nIndex4].m_wCharCode != wCharCode)) + { + if (m_pEnglish_char[nIndex4].m_wCharCode > wCharCode) + { + nIndex3=nIndex4; + if (nIndex2 > nIndex3) break; + nIndex4=(nIndex2 + nIndex3) / 2; + } + else + { + nIndex2=nIndex4; + if (nIndex2 > nIndex3) break; + nIndex4=(nIndex2 + nIndex3) / 2; + } + } + + if ((m_pEnglish_char[nIndex4].m_wCharCode == wCharCode) && + (m_pEnglish_char[nIndex4].m_wBytes > 0)) { + pbyData=new BYTE[m_pEnglish_char[nIndex4].m_wBytes + 1]; + + fileEnglish.seek(m_pEnglish_char[nIndex4].m_dwPosition); + fileEnglish.read((char*)pbyData,m_pEnglish_char[nIndex4].m_wBytes); + } + } + if (pbyData != NULL) + { + if (bEnglishChar) + { + PlotChar(QPoint(x,y),pbyData,m_pEnglish_char[nIndex4].m_wBytes,nLeft,0,m_nHeight_C); + } + else + { + PlotChar(QPoint(x,y),pbyData,m_pChinese_char[nIndex4].m_wBytes,nLeft,0,m_nInternalLeading_E + m_nHeight_E); + } + delete []pbyData; + if (bEnglishChar) nLeft=nLeft + m_pEnglish_char[nIndex4].m_wWidth * m_nHeight_C; + else nLeft=nLeft + m_nWidth_C * (m_nInternalLeading_E + m_nHeight_E); + } + else + { + if (bEnglishChar) nLeft=nLeft + m_pEnglish_char[0].m_wWidth * m_nHeight_C; + else nLeft=nLeft + m_nWidth_C * (m_nInternalLeading_E + m_nHeight_E); + } + + nIndex1++; + } + + fileEnglish.close(); + fileChinese.close(); +} +//画弧,从Start逆时针画到End +void VectorFont::Arc(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect, + int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc) +{ + double dXC,dYC,dRadius; + double dx,dy; + double dAngleS,dAngleE,dAngle,dStep; + double dCos,dSin; + int nCount; + + dXC=((double)nLeftRect + (double)nRightRect) / 2.0; + dYC=((double)nTopRect + (double)nBottomRect) / 2.0; + dRadius=((double)nRightRect - (double)nLeftRect) / 2.0; + + dAngleS=angle_2(dXC,dYC,(double)nXStartArc,(double)nYStartArc); + dAngleE=angle_2(dXC,dYC,(double)nXEndArc,(double)nYEndArc); + while (dAngleE >= dAngleS) dAngleE=dAngleE - 2.0 * PI; + + if ((nXStartArc == nXEndArc) && (nYStartArc == nYEndArc)) + { + dAngleS=0.0; + dAngleE=-2.0 * PI; + } + + dSin=qSin(dAngleS); + dCos=qCos(dAngleS); + dx=dRadius * dCos + dXC; + dy=dRadius * dSin + dYC; + MoveTo(dx+0.5,dy+0.5); + + nCount=120; + dStep=PI / 180.0 * (360.0 / (double)nCount); //3度 + dAngle=dAngleS; + while (dAngle > dAngleE) + { + dAngle=dAngle - dStep; + if (dAngle < dAngleE) dAngle=dAngleE; + dSin=qSin(dAngle); + dCos=qCos(dAngle); + dx=dRadius * dCos + dXC; + dy=dRadius * dSin + dYC; + LineTo(dx+0.5,dy+0.5); + } + +} + +QPoint VectorFont::GetNextCoodinate(WORD wDirection,WORD wLength,QPoint ptPoint) +{ + QPoint ptPoint1; + + switch (wDirection) { + case 0: + ptPoint1.setX( ptPoint.x() + (int)wLength); + ptPoint1.setY(ptPoint.y()); + break; + case 1: + ptPoint1.setX(ptPoint.x() + (int)wLength); + ptPoint1.setY(ptPoint.y() + (int)wLength/2); + break; + case 2: + ptPoint1.setX(ptPoint.x() + (int)wLength); + ptPoint1.setY(ptPoint.y() + (int)wLength); + break; + case 3: + ptPoint1.setX(ptPoint.x() + (int)wLength/2); + ptPoint1.setY(ptPoint.y() + (int)wLength); + break; + case 4: + ptPoint1.setX(ptPoint.x()); + ptPoint1.setY(ptPoint.y() + (int)wLength); + break; + case 5: + ptPoint1.setX(ptPoint.x() - (int)wLength/2); + ptPoint1.setY(ptPoint.y() + (int)wLength); + break; + case 6: + ptPoint1.setX(ptPoint.x() - (int)wLength); + ptPoint1.setY(ptPoint.y() + (int)wLength); + break; + case 7: + ptPoint1.setX(ptPoint.x() - (int)wLength); + ptPoint1.setY(ptPoint.y() + (int)wLength/2); + break; + case 8: + ptPoint1.setX(ptPoint.x() - (int)wLength); + ptPoint1.setY(ptPoint.y()); + break; + case 9: + ptPoint1.setX(ptPoint.x() - (int)wLength); + ptPoint1.setY(ptPoint.y() - (int)wLength/2); + break; + case 10: + ptPoint1.setX(ptPoint.x() - (int)wLength); + ptPoint1.setY(ptPoint.y() - (int)wLength); + break; + case 11: + ptPoint1.setX(ptPoint.x() - (int)wLength/2); + ptPoint1.setY(ptPoint.y() - (int)wLength); + break; + case 12: + ptPoint1.setX(ptPoint.x()); + ptPoint1.setY(ptPoint.y() - (int)wLength); + break; + case 13: + ptPoint1.setX(ptPoint.x() + (int)wLength/2); + ptPoint1.setY(ptPoint.y() - (int)wLength); + break; + case 14: + ptPoint1.setX(ptPoint.x() + (int)wLength); + ptPoint1.setY(ptPoint.y() - (int)wLength); + break; + case 15: + ptPoint1.setX(ptPoint.x() + (int)wLength); + ptPoint1.setY(ptPoint.y() - (int)wLength/2); + break; + } + + return ptPoint1; +} + +//求两点确定的直线与X轴的夹角,在[0,2pi)之间 +//输入参数: +// (startx,starty) 起点 +// (endx,endy) 终点 +//返回值: +// 夹角 +double VectorFont::angle_2(int startx,int starty,int endx,int endy) +{ + //直线与X轴之间的夹角 X轴向量OE(1,0) + double dAngle = 0; + if((endx == startx) && (endy == starty)) + { + return dAngle; + } + //求直线的向量坐标 + double dX = endx - startx; + double dY = endy - starty; + dAngle = qAcos((dX)/(qSqrt(dX*dX + dY*dY))); + return dAngle; +} + +///////////////////////// 计算三点定圆时的圆心和半径 /////////////////////////// +// 输入参数:三个样点(x1,y1),(x2,y2),(x3,y3) +// 算法描述: +// 过(x1,y1),(x2,y2)的中点作垂线L1, +// 过(x2,y2),(x3,y3)的中点作垂线L2, +// 求L1,L2的交点. +// 输出参数: +// 如果不能形成圆返回false, +// 否则返回true其中圆心为(cx,cy),半径=cr. +// 按逆时针方向画弧时,如cr>0 则(x1,y1)是起点,(x3,y3)是终点, +// 如cr<0 则(x3,y3)是起点,(x1,y1)是终点. +// 特别说明:此处所说的逆时针是指显示器而言,如果对于对X向右为正, +// Y向上为正的坐标系来说此处是顺时针 +//bool CircleCR(int x1,int y1,int x2,int y2,int x3,int y3,int& cx,int& cy,int& cr); +//////////////////////////////////////////////////////////////////////////////// +bool VectorFont::CircleCR(double x1,double y1,double x2,double y2,double x3,double y3,double& cx,double& cy,double& cr) +{ + double a1,b1,c1,a2,b2,c2; + if(((x1 ==x2) && (y1==y2)) || ((x1 ==x3) && (y1==y3)) || ((x2 ==x3) && (y2==y3))) + { + return false; + } + a1 = x1 - x2; + b1 = y1 - y2; + c1 = -a1 * (x1 + x2) / 2.0 - b1 * (y1 + y2)/2.0; + a2 = x3 - x2; + b2 = y3 - y2; + c2 = -a2 * (x2 + x3) / 2.0 - b2 * (y2 + y3)/2.0; + + double D = a1*b2 - a2*b1; + if(D == 0)//两直线平行 + { + return false; + } + + cx = (b1*c2 - b2*c1)/D; + cy = (c1*a2 - c2*a1)/D; + + //用圆心和其中一个点求距离得到半径: + cr = qSqrt((cx - x1)*(cx - x1) + (cy - y1)*(cy - y1)); + return true; +} + diff --git a/datafile/hpgl/vectorfont.h b/datafile/hpgl/vectorfont.h new file mode 100644 index 0000000..b21390d --- /dev/null +++ b/datafile/hpgl/vectorfont.h @@ -0,0 +1,132 @@ +#ifndef VECTORFONT_H +#define VECTORFONT_H + +#include +#include +#include "typedef.h" + +class CChinese_char +{ +public: + WORD m_wCharCode; + WORD m_wBytes; + DWORD m_dwPosition; + + CChinese_char() + { + m_wCharCode=0; + m_wBytes=0; + m_dwPosition=0; + } + CChinese_char(const CChinese_char &a) + { + m_wCharCode=a.m_wCharCode; + m_wBytes=a.m_wBytes; + m_dwPosition=a.m_dwPosition; + } + CChinese_char(WORD wCharCode,WORD wBytes,DWORD dwPosition) + { + m_wCharCode=wCharCode; + m_wBytes=wBytes; + m_dwPosition=dwPosition; + } + ~CChinese_char() {} + CChinese_char operator=(const CChinese_char &a) + { + m_wCharCode=a.m_wCharCode; + m_wBytes=a.m_wBytes; + m_dwPosition=a.m_dwPosition; + return *this; + } +}; + +class CEnglish_char +{ +public: + WORD m_wCharCode; + WORD m_wBytes; + WORD m_wWidth; + DWORD m_dwPosition; + + CEnglish_char() + { + m_wCharCode=0; + m_wBytes=0; + m_wWidth=0; + m_dwPosition=0; + } + CEnglish_char(const CEnglish_char &a) + { + m_wCharCode=a.m_wCharCode; + m_wBytes=a.m_wBytes; + m_wWidth=a.m_wWidth; + m_dwPosition=a.m_dwPosition; + } + CEnglish_char(WORD wCharCode,WORD wBytes,WORD wWidth,DWORD dwPosition) + { + m_wCharCode=wCharCode; + m_wBytes=wBytes; + m_wWidth=wWidth; + m_dwPosition=dwPosition; + } + ~CEnglish_char() {} + CEnglish_char operator=(const CEnglish_char &a) + { + m_wCharCode=a.m_wCharCode; + m_wBytes=a.m_wBytes; + m_wWidth=a.m_wWidth; + m_dwPosition=a.m_dwPosition; + return *this; + } +}; +class VectorFont : public QObject +{ + Q_OBJECT +public: + explicit VectorFont(QObject *parent = 0); + ~VectorFont(); + void IniVectorFont(); + + +signals: + void siLineTo(bool bl,QPoint point); + void siMoveTo(bool bl,QPoint point); + +public slots: +protected: + + double m_iDPMM; //长度数据单位:m_iDPMM(每毫米点) + double m_dRake; //倾斜角(第1个字符原点到最后1个字符原点的连线的角度),单位:弧度 + + QString m_workPath; + + //QList m_aChinese_char; + //QList m_aEnglish_char; + CChinese_char *m_pChinese_char; + CEnglish_char *m_pEnglish_char; + int m_nChinese_char_count; + int m_nEnglish_char_count; + int m_nInternalLeading_E,m_nHeight_E,m_nDescent_E; //m_nHeight_E是windows中字体的Ascent-InternalLeading + int m_nHeight_C,m_nWidth_C; +public: + + void PlotChar(QPoint ptPointLU,BYTE*pbyData,WORD wBytes,int nLeft,int nDown,int nFontScale); + QPoint CPToLP(QPoint ptCP,int nHeight,QPoint ptPointLU,double dSin,double dCos,double dScale); + void TextOutString(int x, int y, const char* lpszString, int nCount); + void Arc(int nLeftRect,int nTopRect,int nRightRect,int nBottomRect,int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc); + QPoint GetNextCoodinate(WORD wDirection,WORD wLength,QPoint ptPoint); + void MoveTo(QPoint ptPoint); + void MoveTo(long x,long y); + void LineTo(QPoint ptPoint); + void LineTo(long x,long y); + double angle_2(int startx,int starty,int endx,int endy); + bool CircleCR(double x1,double y1,double x2,double y2,double x3,double y3,double& cx,double& cy,double& cr); + + double m_dFontHeight; //字的高度 + double m_dFontAngle;//指定每行文本输出时相对于设备x轴的角度,其单位为1/10度 + + + +}; + +#endif // VECTORFONT_H diff --git a/datafile/hpgl/vectorsqrt.cpp b/datafile/hpgl/vectorsqrt.cpp new file mode 100644 index 0000000..433e84c --- /dev/null +++ b/datafile/hpgl/vectorsqrt.cpp @@ -0,0 +1,4501 @@ +#include "vectorsqrt.h" + +#include + +#include "comm/crc16.h" + +//--------------------------------------------------------------------------------------------------------- + +VSqrtItem::VSqrtItem(QObject *parent) : + QObject(parent), + m_sqrttype(0), + m_begx(0), + m_begy(0), + m_midx(0), + m_midy(0), + m_midx2(0), + m_midy2(0), + m_endx(0), + m_endy(0), + m_code(0), + m_ownsteplock(0), + m_stepSize(0), + m_blockNum(0), + m_blockTimes(0), + m_blockjumps(0), + m_elockNum(0), + m_elockTimes(0), + m_elockjumps(0) +{ + +} + +VSqrtItem::VSqrtItem(const VSqrtItem & item) : + QObject() +{ + CopyData(item); +} + +VSqrtItem& VSqrtItem::operator=(const VSqrtItem & item) +{ + CopyData(item); + return * this; +} + +void VSqrtItem::CopyData(const VSqrtItem & item) +{ + if (this != &item) + { + this->m_sqrttype = item.m_sqrttype; + this->m_begx = item.m_begx; + this->m_begy = item.m_begy; + this->m_endx = item.m_endx; + this->m_endy = item.m_endy; + this->m_midx = item.m_midx; + this->m_midy = item.m_midy; + this->m_midx2 = item.m_midx2; + this->m_midy2 = item.m_midy2; + this->m_code = item.m_code; + this->m_ownsteplock = item.m_ownsteplock; + this->m_stepSize = item.m_stepSize; + this->m_blockNum = item.m_blockNum; + this->m_blockTimes = item.m_blockTimes; + this->m_blockjumps = item.m_blockjumps; + this->m_elockNum = item.m_elockNum; + this->m_elockTimes = item.m_elockTimes; + this->m_elockjumps = item.m_elockjumps; + } +} + +void VSqrtItem::InitVSItem() +{ + m_sqrttype = 0; + m_begx = 0; + m_begy = 0; + m_endx = 0; + m_endy = 0; + m_midx = 0; + m_midy = 0; + m_midx2 = 0; + m_midy2 = 0; + m_code = 0; + m_ownsteplock = 0; + m_stepSize = 0; + m_blockNum = 0; + m_blockTimes = 0; + m_blockjumps = 0; + m_elockNum = 0; + m_elockTimes = 0; + m_elockjumps = 0; +} + +//--------------------------------------------------------------------------------------------------------- +#define MAX_ITEM_NUM (100*10000) + + +VectorSqrt::VectorSqrt(QObject *parent) : + QObject(parent), + m_filename(), + m_anchorSel(0), + m_vSqitItemList(), + m_para_stepSize(0), + m_para_blockNum(0), + m_para_blockTimes(0), + m_para_blockjumps(0), + m_para_elockNum(0), + m_para_elockTimes(0), + m_para_elockjumps(0) +{ + +} + +VectorSqrt::~VectorSqrt() +{ + m_vSqitItemList.clear(); + m_filename.clear(); +} + +VectorSqrt::VectorSqrt(const VectorSqrt & item) : + QObject() +{ + CopyData(item); +} + +VectorSqrt& VectorSqrt::operator=(const VectorSqrt & item) +{ + CopyData(item); + return * this; +} + +void VectorSqrt::CopyData(const VectorSqrt & item) +{ + if (this != &item) + { + this->m_filename = item.m_filename; + this->m_anchorSel = item.m_anchorSel; + this->m_vSqitItemList = item.m_vSqitItemList; + this->m_para_stepSize = item.m_para_stepSize; + this->m_para_blockNum = item.m_para_blockNum; + this->m_para_blockTimes = item.m_para_blockTimes; + this->m_para_blockjumps = item.m_para_blockjumps; + this->m_para_elockNum = item.m_para_elockNum; + this->m_para_elockTimes = item.m_para_elockTimes; + this->m_para_elockjumps = item.m_para_elockjumps; + } +} + +void VectorSqrt::InitVSqrt(QString name) +{ + m_filename = name; // 名称 + m_vSqitItemList.clear(); // 图形列表 + m_para_stepSize = 0; // 步长 + m_para_blockNum = 0; // 起始锁针针数 + m_para_blockTimes = 0; // 起始锁针次数 + m_para_blockjumps = 0; // 起始跳过针数 + m_para_elockNum = 0; // 结束锁针针数 + m_para_elockTimes = 0; // 结束锁针次数 + m_para_elockjumps = 0; // 结束跳过针数 +} +void VectorSqrt::SetAnchor(int nX,int nY) +{ + m_anchorX = nX; + m_anchorY = nY; +} + +void VectorSqrt::SetBegin(int nX,int nY) +{ + m_beginX = nX; + m_beginY = nY; +} +#if 0 +int VectorSqrt::CreateDs16FromSqrt(QByteArray & ds16Ary)// +{ + int rslt; + ds16Ary.clear(); + rslt = 0; + if (m_vSqitItemList.size() != 0) + { + double threex[3], threey[3]; + + int begx, begy, begr, begflag; + + int paraBLockNum, paraBLockTimes, paraBLockJumps; + int paraELockNum, paraELockTimes, paraELockJumps; + int blockNum, blockTimes; + int elockNum, elockTimes; + int blockjumps, elockjumps; + int stepSize, sqrtNum; + int actx, acty, actr; + int i, j, k, idx; + int stepNumber, curtNumber, totalNumber; + int n, cutflag; + int offsetdr = 0; qDebug() << offsetdr ; + + u8 ctrl, oldctrl, attr; + + const int maxitemnum = MAX_ITEM_NUM; + + DataItem * dataItemArray = new DataItem[maxitemnum]; + if (dataItemArray == NULL) + { + return -1; + } + DataItem * pSteps, * pData, * pTemp; + pSteps = dataItemArray; // 数据存放地址 + //------------------ + + sqrtNum = m_vSqitItemList.size(); // 图形个数 + + begx = m_vSqitItemList.at(0).m_begx; + begy = m_vSqitItemList.at(0).m_begy; + begr = 0; + + actx = begx; + acty = begy; + actr = 0; + + begflag = 0; + totalNumber = 0; + oldctrl = 0; + ctrl = 0; + cutflag = 0; + + // printf("\t sqrtNum = %d\r\n", sqrtNum); + + //------------------ + // 生成文件内容 + for (idx = 0; idx < sqrtNum; idx++) + { + if (m_vSqitItemList.at(idx).m_ownsteplock != 0) // 使用单独的针步和回针参数 + { + stepSize = m_vSqitItemList.at(idx).m_stepSize; // 分割针步大小 + paraBLockNum = m_vSqitItemList.at(idx).m_blockNum; + paraBLockTimes = m_vSqitItemList.at(idx).m_blockTimes; + paraBLockJumps = m_vSqitItemList.at(idx).m_blockjumps; + paraELockNum = m_vSqitItemList.at(idx).m_elockNum; + paraELockTimes = m_vSqitItemList.at(idx).m_elockTimes; + paraELockJumps = m_vSqitItemList.at(idx).m_elockjumps; + } + else + { + stepSize = m_para_stepSize; // 分割针步大小 + paraBLockNum = m_para_blockNum; + paraBLockTimes = m_para_blockTimes; + paraBLockJumps = m_para_blockjumps; + paraELockNum = m_para_elockNum; + paraELockTimes = m_para_elockTimes; + paraELockJumps = m_para_elockjumps; + } + +#if (0) + qDebug("m_vSqitItemList[%d] para:\r\n", idx); + + qDebug("\t stepSize = %d\r\n", stepSize); + qDebug("\t blockNum = %d\r\n", blockNum); + qDebug("\t blockTimes = %d\r\n", blockTimes); + qDebug("\t blockjumps = %d\r\n", blockjumps); + qDebug("\t elockNum = %d\r\n", elockNum); + qDebug("\t elockTimes = %d\r\n", elockTimes); + qDebug("\t elockjumps = %d\r\n", elockjumps); +#endif + + //------------------ + // 起始回针参数处理 + if (paraBLockTimes > 0 && paraBLockNum > 0) + { + if (paraBLockJumps > paraBLockTimes*paraBLockNum) + { + paraBLockNum = 0; + paraBLockTimes = 0; + paraBLockJumps = 0; + } + } + else + { + paraBLockNum = 0; + paraBLockTimes = 0; + paraBLockJumps = 0; + } + while (paraBLockJumps >= paraBLockNum && paraBLockTimes > 1) // 保证jumps小于locknums + { + paraBLockJumps -= paraBLockNum; + paraBLockTimes--; + } + // 结束回针参数处理 + if (paraELockTimes > 0 && paraELockNum > 0) + { + if (paraELockJumps > paraELockTimes*paraELockNum) + { + paraELockNum = 0; + paraELockTimes = 0; + paraELockJumps = 0; + } + } + else + { + paraELockNum = 0; + paraELockTimes = 0; + paraELockJumps = 0; + } + while (paraELockJumps >= paraELockNum && paraELockTimes > 1) // 保证jumps小于locknums + { + paraELockJumps -= paraELockNum; + paraELockTimes--; + } + //------------------ + +#if (0) + qDebug("calc para:\r\n"); + + qDebug("\t sqrtNum = %d\r\n", sqrtNum); + qDebug("\t stepSize = %d\r\n", stepSize); + qDebug("\t blockNum = %d\r\n", paraBLockNum); + qDebug("\t blockTimes = %d\r\n", paraBLockTimes); + qDebug("\t blockjumps = %d\r\n", paraBLockJumps); + qDebug("\t elockNum = %d\r\n", paraELockNum); + qDebug("\t elockTimes = %d\r\n", paraELockTimes); + qDebug("\t elockjumps = %d\r\n", paraELockJumps); +#endif + +#if (0) + qDebug("\t begx = %f\r\n", m_vSqitItemList.at(idx).m_begx); + qDebug("\t begy = %f\r\n", m_vSqitItemList.at(idx).m_begy); + qDebug("\t endx = %f\r\n", m_vSqitItemList.at(idx).m_endx); + qDebug("\t endy = %f\r\n", m_vSqitItemList.at(idx).m_endy); + qDebug("\t midx = %f\r\n", m_vSqitItemList.at(idx).m_midx); + qDebug("\t midy = %f\r\n", m_vSqitItemList.at(idx).m_midy); +#endif + + //------------------ + if (begflag != 0) // 非起始,插入偏移数据 + { + if (fabs(m_vSqitItemList.at(idx).m_begx - m_vSqitItemList.at(idx-1).m_endx) > 1 || + fabs(m_vSqitItemList.at(idx).m_begy - m_vSqitItemList.at(idx-1).m_endy) > 1 || + 0 ) + { + // 自动插入偏移数据 + threex[0] = m_vSqitItemList.at(idx-1).m_endx; + threey[0] = m_vSqitItemList.at(idx-1).m_endy; + threex[1] = m_vSqitItemList.at(idx).m_begx; + threey[1] = m_vSqitItemList.at(idx).m_begy; + threex[2] = m_vSqitItemList.at(idx).m_begx; + threey[2] = m_vSqitItemList.at(idx).m_begy; // 三点共线,作为直线 + + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, S16_MAX/2, pSteps, DATA_OFFSET); + + pSteps += stepNumber; + totalNumber += stepNumber; + } + + } + + oldctrl = ctrl; + ctrl = m_vSqitItemList.at(idx).m_code; + + blockNum = 0; blockTimes = 0; blockjumps = 0; + elockNum = 0; elockTimes = 0; elockjumps = 0; + cutflag = 0; + + if ((ctrl == DATA_SEWING || + ctrl == DATA_SYNCSEW)) + { + if (oldctrl != ctrl) + { + blockNum = paraBLockNum; // 起始锁针针数 + blockTimes = paraBLockTimes; // 起始锁针次数 + blockjumps = paraBLockJumps; // 起针跳过针数 + if (blockTimes > 0) + { + if (blockjumps > blockTimes*blockNum) + { + blockTimes = 0; + blockNum = 0; + blockjumps = 0; + } + } + else + { + blockTimes = 0; + blockNum = 0; + blockjumps = 0; + } + } + + if ( idx+1 >= sqrtNum || m_vSqitItemList.at(idx+1).m_code != ctrl) + { + elockNum = paraELockNum; // 结束锁针针数 + elockTimes = paraELockTimes; // 结束锁针次数 + elockjumps = paraELockJumps; // 结束跳过针数 + cutflag = 1; + if (elockTimes > 0) + { + if (elockjumps > elockTimes*elockNum) + { + elockTimes = 0; + elockNum = 0; + elockjumps = 0; + } + } + else + { + elockTimes = 0; + elockNum = 0; + elockjumps = 0; + } + } + } + + threex[0] = m_vSqitItemList.at(idx).m_begx; + threey[0] = m_vSqitItemList.at(idx).m_begy; + threex[1] = m_vSqitItemList.at(idx).m_midx; + threey[1] = m_vSqitItemList.at(idx).m_midy; + threex[2] = m_vSqitItemList.at(idx).m_endx; + threey[2] = m_vSqitItemList.at(idx).m_endy; + + stepNumber = CalcCurve(threex, threey, NULL, NULL, NULL, stepSize, NULL, ctrl); + curtNumber = stepNumber + blockNum*blockTimes + elockNum*elockTimes - blockjumps - elockjumps;; + + // qDebug("stepNumber = %d, cur totalNumber=%d:\r\n", stepNumber, curtNumber); + + pData = pSteps + (blockNum*blockTimes) - blockjumps; + + n = CalcCurve(threex, threey, &actx, &acty, &actr, stepSize, pData, ctrl); + if (n != stepNumber) + { + // qDebug("create number =%d, is not equal to stepNumber=%d:\r\n", n, stepNumber); + } + + if (begflag == 0) + { + begr = pData->dr; + pData->dr = 0; + } + + //------------------ + // 倒序添加起针锁针 +#if (0) + // 起始锁针信息 + printf("before add lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + pTemp = pData - 1; + k = blockTimes*blockNum; + for (i = 0; i < blockTimes; i++) + { + if (i%2 == 0) // 奇数锁针 + { + // printf("ji shu:\r\n"); + for (j = 0; j < blockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + k--; + if (k < blockjumps) // 跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp--; + } + } + else // 偶数锁针 + { + // printf("ou shu:\r\n"); + for (j = blockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + + k--; + if (k < blockjumps) // 跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp--; + } + } + } + // 正向扫描,修正起针回针中的dr + k = blockTimes*blockNum; + pTemp = pData - k; + if(blockTimes != 0 ) + { + for (i = 0; i <= blockTimes; i++) // 跳过第一次锁针(偶数),且 + { + if (i%2 == 0) // 偶数锁针 + { + if (i == 0) // 第一针, 这里不做处理,后面添加单独运动dr的offset + { + } + else + { + pTemp->dr = 0; + } + pTemp += blockNum; + } + else // 奇数锁针 + { + pTemp += blockNum - 1 ; + pTemp->dr = 0; + pTemp++; + } + } + } +#if (0) + // 结束锁针信息 + printf("after add begin lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + //------------------ + // 顺序添加末针锁针 + pTemp = pData + stepNumber; + k = 0; + for (i = 0; i < elockTimes; i++) + { + if (i%2 == 0) // 奇数锁针 + { + for (j = 0; j < elockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + + k++; + if (k > elockTimes*elockNum - elockjumps) // 结束跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp++; + } + } + else + { + for (j = elockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + k++; + if (k > elockTimes*elockNum - elockjumps) // 结束跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp++; + } + } + } + +#if (0) + printf("after add end lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + //------------------ + + stepNumber = curtNumber; + + if (cutflag != 0) // 缝纫针步添加剪线码 + { + // 添加剪线码 + pSteps[stepNumber].ctrl = DATA_CUTTRD; + pSteps[stepNumber].attr = 0; + pSteps[stepNumber].dx = 0; + pSteps[stepNumber].dy = 0; + pSteps[stepNumber].dr = 0; + stepNumber++; + } + +#if (0) + printf("after jump lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + + pSteps += stepNumber; + totalNumber += stepNumber; + begflag = 1; + } // end of for(idx...... + + //------------------ + // 最后一针添加结束码 + dataItemArray[totalNumber].ctrl = DATA_END; + dataItemArray[totalNumber].attr = 0; + dataItemArray[totalNumber].dx = 0; + dataItemArray[totalNumber].dy = 0; + dataItemArray[totalNumber].dr = 0; + + totalNumber++; + if (rslt != 0) + { + qDebug("no enough item mem"); + } + +#if (0) + printf("after calc, begx=%d, begy=%d, stepNumber=%d\r\n", begx, begy, totalNumber); +#endif + +#if (1) + // 剪线码移到缝纫数据之后 + pData = dataItemArray; // 源 + begflag = 0; + + for (i = 0; i < totalNumber; i++) + { + if ((pData->ctrl == DATA_SEWING || pData->ctrl == DATA_SYNCSEW)) + { + begflag = 1; + } + else if (pData->ctrl == DATA_OFFSET) + { + if (begflag == 1) + { + pSteps = pData; + begflag = 2; + } + else if (begflag != 2) + { + begflag = 0; + } + } + else if (pData->ctrl == DATA_CUTTRD) + { + if (begflag == 2) + { + // 交换 pSteps 和 pData + DataItem tmpItem; + memcpy(&tmpItem, pData, sizeof(DataItem)); + memcpy(pData, pSteps, sizeof(DataItem)); + memcpy(pSteps, &tmpItem, sizeof(DataItem)); + } + begflag = 0; + } + else + { + begflag = 0; + } + pData++; + } + +#endif + pData = dataItemArray; // 源 + pSteps = pData; // 目标 + // 扫描生成数据,确定起点坐标,合并offset数据 + // 起点坐标 + begr = pData[0].dr; // 第一个针步,dr是从0开始的变化量 + pData[0].dr = 0; // 设置第一个针步的变化量为0 + + i = 0; +#if (0) + for (i = 0; i < totalNumber; i++) + { + if (pData->ctrl != DATA_OFFSET) // 起始的offset合并到起点坐标 + { + break; + } + + begx += pData->dx; + begy += pData->dy; + begr += pData->dr; // 改变起针位置 + pData++; // 源后移 + } +#endif + + begflag = 0; + actr = begr; +#if (0) + int offset_dr; + + // 继续扫描生成数据,合并offset数据 + for (i = i, j = 0; i < totalNumber; i++) + { + if (pData->ctrl == DATA_OFFSET) + { + if (begflag == 0) + { + // 初始化offset计数 + threex[0] = 0; + threey[0] = 0; + threex[1] = 0; + threey[1] = 0; + threex[2] = 0; + threey[2] = 0; + offset_dr = 0; + begflag = 1; + } + + threex[2] += pData->dx; + threey[2] += pData->dy; + offset_dr += pData->dr; + } + else + { + if (begflag != 0 && pData->ctrl != DATA_END) + { + // 重新插入偏移数据 + actx = 0; + acty = 0; + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, S16_MAX*3/5, pSteps, DATA_OFFSET); + pSteps->dr = offset_dr ; + + pSteps += stepNumber; + j += stepNumber; + begflag = 0; + } + if (pSteps != pData) + { + memcpy(pSteps, pData, sizeof(DataItem)); + } + j++; + actr += pSteps->dr; + pSteps++; + } + + pData++; + } + + totalNumber = j; +#endif + +#if (0) + printf("before write begx=%d, begy=%d, stepNumber=%d\r\n", begx, begy, totalNumber); +#endif + +#ifdef used_mac_DHQ // 1 插入小的数据 0 不插入小的数据 + + DataItem * cp_dataItemArray = new DataItem[totalNumber]; + + memcpy( cp_dataItemArray , dataItemArray , sizeof( DataItem )*totalNumber); + + j = 0 ; + for (int var = 0; var < totalNumber; ++var) + { + if((var + 1) > totalNumber) + { + break; + } + else if( + (cp_dataItemArray[var].ctrl == cp_dataItemArray[var + 1].ctrl) + && + ((cp_dataItemArray[var].ctrl == DATA_SEWING)|| + (cp_dataItemArray[var].ctrl == DATA_SECF_SEW)|| + (cp_dataItemArray[var].ctrl == DATA_SYNCSEW) + ) + && + (fabs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len) > + 1.8 * m_rvsf_info.i_dense_step) + ) + { + DataItem temp ; +#if 1 + memset( &temp , 0 , sizeof (DataItem )); + + int len = cp_dataItemArray[var].len ; + + if( cp_dataItemArray[ var ].len > cp_dataItemArray[ var + 1 ].len ) + { + len = cp_dataItemArray[ var + 1 ].len ; + } + else if( cp_dataItemArray[var].len < cp_dataItemArray[var + 1].len) + { + len = cp_dataItemArray[ var ].len ; + } + + if( abs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len ) > len*0.3 ) + { + memcpy( &(temp) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + temp.attr |= ATTR_RESEW; + memcpy( &(dataItemArray[j]) , &(temp) , sizeof( DataItem )); + j++; + } + else if( abs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len ) > len*0.3 ) + { + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + j++; + var++; + memcpy( &(temp) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + temp.attr |= ATTR_RESEW; + memcpy( &(dataItemArray[j]) , &(temp) , sizeof( DataItem )); + j++; + } +#endif + +#if 0 + + if( cp_dataItemArray[var].len > cp_dataItemArray[var + 1 ].len) + { + + //两个索引都退两个 + var -= 2; + j -= 2; + + //复制第一个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.attr |= ATTR_RESEW; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + var++; + + //复制第二个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + var++; + } + else if( cp_dataItemArray[var + 1].len > cp_dataItemArray[var].len) + { + + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + var++; + j++ ; + + //复制第一个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.attr |= ATTR_RESEW; + + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + var++; + + //复制第二个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + var++; + } +#endif + } + else + { + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + j++ ; + } + } + delete [] cp_dataItemArray; + totalNumber = j; +#endif + + + // dataItemArray + + for( int i = 0 ; i < (totalNumber -1); i++) + { + if( + ( dataItemArray[i].ctrl == DATA_OFFSET ) + && + ( + ( dataItemArray[i + 1 ].ctrl == DATA_RKNIFE ) + ||( dataItemArray[i + 1 ].ctrl == DATA_SKNIFE ) + ) + ) + { + dataItemArray[i ].dr += dataItemArray[i + 1 ].dr; + dataItemArray[i + 1 ].dr = 0 ; + } + } + + // 写文件头 + DataFileHead fileHead; // 数据文件头描述 + memset(&fileHead, 0, sizeof(DataFileHead)); + + m_filename = "test.plt"; + QByteArray ba = m_filename.toLatin1(); // ISO-8859-1 文件名称 + int cpsize = ba.size(); + if (cpsize > 32) + { + cpsize = 32; + } + + + memcpy(fileHead.fileName, (char*)ba.data(), cpsize); + + fileHead.dataSize = totalNumber*sizeof(DataItem); // 文件长度 + fileHead.itemNums = totalNumber; // 有效针数 + fileHead.bytesPerItem = sizeof(DataItem); // 每针占的字节数 + fileHead.bytesPerBlk = 1024; // 文件内容划分块大小 + + fileHead.dataChecksum = CalcCheckSum32((u8*)(dataItemArray), totalNumber*sizeof(DataItem)); // 花样数据累加校验和 + fileHead.checkCrc = CalcCrc16((u8*)(&fileHead), 6*sizeof(u32)); // 前6个字段CRC校验 + + + s32 minx, miny, maxx, maxy; + GetDataMinMax(dataItemArray, totalNumber, minx, miny, maxx, maxy); + + fileHead.minX = minx - minx + m_beginX; + fileHead.maxX = maxx - minx + m_beginX; + fileHead.minY = miny - miny + m_beginY; + fileHead.maxY = maxy - miny + m_beginY; + + fileHead.beginX = m_beginX ; + fileHead.beginY = m_beginY ; + + fileHead.anchorX = m_anchorX; + fileHead.anchorY = m_anchorY; // 定位点 + + /* + + begx + + begy + + begx + + begy +*/ +#if (0) + if( 1 ) + { + m_anchorSel = 1 ; // 当文件是 qui 的时候 + + fileHead.beginX = begx; + fileHead.beginY = begy; + } + else if( 0 ) + { + m_anchorSel = 0 ; //当文件是 rvsf 的时候 + + fileHead.beginX = m_rvsf_info.i_Gantry; + fileHead.beginY = m_rvsf_info.i_Head_B; + fileHead.beginR = begr; // 起始点坐标 + + fileHead.beginX2 = m_rvsf_info.i_Gantry; + fileHead.beginY2 = m_rvsf_info.i_Head_A; + fileHead.beginR2 = 0; + + if( fileHead.beginX2 < fileHead.minX) + { + fileHead.minX = fileHead.beginX2; + } + if( fileHead.beginX2 > fileHead.maxX) + { + fileHead.maxX = fileHead.beginX2; + } + if( fileHead.beginY2 < fileHead.minY) + { + fileHead.minY = fileHead.beginY2; + } + if( fileHead.beginY2 > fileHead.maxY) + { + fileHead.maxY = fileHead.beginY2; + } + } + // 定位点选择; 0, 和起点重合; 1,图形的左下角; 2, 图形的右下角; 3, 图形的右上角; 4, 图形的左上角; 5, 图形的中心 + switch (m_anchorSel) + { + case 1: // 1,图形的左下角 + fileHead.anchorX = fileHead.minX; + fileHead.anchorY = fileHead.minY; // 定位点 + break; + case 2: // 2,图形的右下角 + fileHead.anchorX = fileHead.maxX; + fileHead.anchorY = fileHead.minY; // 定位点 + break; + case 3: // 3,图形的右上角 + fileHead.anchorX = fileHead.maxX; + fileHead.anchorY = fileHead.maxY; // 定位点 + break; + case 4: // 4,图形的左上角 + fileHead.anchorX = fileHead.minX; + fileHead.anchorY = fileHead.maxY; // 定位点 + break; + default: + + fileHead.anchorX = fileHead.beginX; + fileHead.anchorY = fileHead.beginY; // 定位点 + + fileHead.anchorX2 = fileHead.beginX2 ; + fileHead.anchorY2 = fileHead.beginY2 ; // 定位点 + + break; + } +#endif + + + +#if (0) + printf("finial write:\r\n"); + for (i = 0; i < stepNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + // 拷贝数据 + ds16Ary.resize(sizeof(DataFileHead)+totalNumber*sizeof(DataItem)); + memcpy (ds16Ary.data(), &fileHead, sizeof(DataFileHead)); + memcpy (&m_fileHead, &fileHead, sizeof(DataFileHead)); + memcpy (ds16Ary.data() + sizeof(DataFileHead), dataItemArray, totalNumber*sizeof(DataItem)); + + delete []dataItemArray; + } + + return rslt; +} + +#endif +#if 1 +int VectorSqrt::CreateDs16FromSqrt(QByteArray & ds16Ary)// +{ + int rslt; + ds16Ary.clear(); + rslt = 0; + if (m_vSqitItemList.size() != 0) + { + double threex[3], threey[3]; + + int begx, begy, begr, begflag; + + int paraBLockNum, paraBLockTimes, paraBLockJumps; + int paraELockNum, paraELockTimes, paraELockJumps; + int blockNum, blockTimes; + int elockNum, elockTimes; + int blockjumps, elockjumps; + int stepSize, sqrtNum; + int actx, acty, actr; + int i, j, k, idx; + int stepNumber, curtNumber, totalNumber; + int n, cutflag; + int offsetdr = 0; + + u8 ctrl, oldctrl, attr; + + const int maxitemnum = MAX_ITEM_NUM; + + DataItem * dataItemArray = new DataItem[maxitemnum]; + if (dataItemArray == NULL) + { + return -1; + } + DataItem * pSteps, * pData, * pTemp; + pSteps = dataItemArray; // 数据存放地址 + //------------------ + + sqrtNum = m_vSqitItemList.size(); // 图形个数 + + begx = m_vSqitItemList.at(0).m_begx; + begy = m_vSqitItemList.at(0).m_begy; + begr = 0; + + actx = begx; + acty = begy; + actr = 0; + + begflag = 0; + totalNumber = 0; + oldctrl = 0; + ctrl = 0; + cutflag = 0; + + // printf("\t sqrtNum = %d\r\n", sqrtNum); + + //------------------ + // 生成文件内容 + for (idx = 0; idx < sqrtNum; idx++) + { + if (m_vSqitItemList.at(idx).m_ownsteplock != 0) // 使用单独的针步和回针参数 + { + stepSize = m_vSqitItemList.at(idx).m_stepSize; // 分割针步大小 + paraBLockNum = m_vSqitItemList.at(idx).m_blockNum; + paraBLockTimes = m_vSqitItemList.at(idx).m_blockTimes; + paraBLockJumps = m_vSqitItemList.at(idx).m_blockjumps; + paraELockNum = m_vSqitItemList.at(idx).m_elockNum; + paraELockTimes = m_vSqitItemList.at(idx).m_elockTimes; + paraELockJumps = m_vSqitItemList.at(idx).m_elockjumps; + } + else + { + stepSize = m_para_stepSize; // 分割针步大小 + paraBLockNum = m_para_blockNum; + paraBLockTimes = m_para_blockTimes; + paraBLockJumps = m_para_blockjumps; + paraELockNum = m_para_elockNum; + paraELockTimes = m_para_elockTimes; + paraELockJumps = m_para_elockjumps; + } + +#if (0) + qDebug("m_vSqitItemList[%d] para:\r\n", idx); + + qDebug("\t stepSize = %d\r\n", stepSize); + qDebug("\t blockNum = %d\r\n", blockNum); + qDebug("\t blockTimes = %d\r\n", blockTimes); + qDebug("\t blockjumps = %d\r\n", blockjumps); + qDebug("\t elockNum = %d\r\n", elockNum); + qDebug("\t elockTimes = %d\r\n", elockTimes); + qDebug("\t elockjumps = %d\r\n", elockjumps); +#endif + + //------------------ + // 起始回针参数处理 + /*if (paraBLockTimes > 0 && paraBLockNum > 0) + { + if (paraBLockJumps > paraBLockTimes*paraBLockNum) + { + paraBLockNum = 0; + paraBLockTimes = 0; + paraBLockJumps = 0; + } + } + else + { + paraBLockNum = 0; + paraBLockTimes = 0; + paraBLockJumps = 0; + } + while (paraBLockJumps >= paraBLockNum && paraBLockTimes > 1) // 保证jumps小于locknums + { + paraBLockJumps -= paraBLockNum; + paraBLockTimes--; + } + // 结束回针参数处理 + if (paraELockTimes > 0 && paraELockNum > 0) + { + if (paraELockJumps > paraELockTimes*paraELockNum) + { + paraELockNum = 0; + paraELockTimes = 0; + paraELockJumps = 0; + } + } + else + { + paraELockNum = 0; + paraELockTimes = 0; + paraELockJumps = 0; + } + while (paraELockJumps >= paraELockNum && paraELockTimes > 1) // 保证jumps小于locknums + { + paraELockJumps -= paraELockNum; + paraELockTimes--; + }*/ + //------------------ + +#if (0) + qDebug("calc para:\r\n"); + + qDebug("\t sqrtNum = %d\r\n", sqrtNum); + qDebug("\t stepSize = %d\r\n", stepSize); + qDebug("\t blockNum = %d\r\n", paraBLockNum); + qDebug("\t blockTimes = %d\r\n", paraBLockTimes); + qDebug("\t blockjumps = %d\r\n", paraBLockJumps); + qDebug("\t elockNum = %d\r\n", paraELockNum); + qDebug("\t elockTimes = %d\r\n", paraELockTimes); + qDebug("\t elockjumps = %d\r\n", paraELockJumps); +#endif + +#if (0) + qDebug("\t begx = %f\r\n", m_vSqitItemList.at(idx).m_begx); + qDebug("\t begy = %f\r\n", m_vSqitItemList.at(idx).m_begy); + qDebug("\t endx = %f\r\n", m_vSqitItemList.at(idx).m_endx); + qDebug("\t endy = %f\r\n", m_vSqitItemList.at(idx).m_endy); + qDebug("\t midx = %f\r\n", m_vSqitItemList.at(idx).m_midx); + qDebug("\t midy = %f\r\n", m_vSqitItemList.at(idx).m_midy); +#endif + + //------------------ + if (begflag != 0) // 非起始,插入偏移数据 + { + if (fabs(m_vSqitItemList.at(idx).m_begx - m_vSqitItemList.at(idx-1).m_endx) > 1 || + fabs(m_vSqitItemList.at(idx).m_begy - m_vSqitItemList.at(idx-1).m_endy) > 1 || + 0 ) + { + // 自动插入偏移数据 + threex[0] = m_vSqitItemList.at(idx-1).m_endx; + threey[0] = m_vSqitItemList.at(idx-1).m_endy; + threex[1] = m_vSqitItemList.at(idx).m_begx; + threey[1] = m_vSqitItemList.at(idx).m_begy; + threex[2] = m_vSqitItemList.at(idx).m_begx; + threey[2] = m_vSqitItemList.at(idx).m_begy; // 三点共线,作为直线 + + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, S16_MAX/2, pSteps, DATA_OFFSET); + if (totalNumber + stepNumber >= maxitemnum) + { + rslt = -1; + break; + } + +#if 1 // 暂不插入偏移数据 + pSteps += stepNumber; + totalNumber += stepNumber; +#endif + + if (stepNumber != 0) + { + ctrl = DATA_OFFSET; + } + } + else + { + // 偏差小于1个单位, 不支持插入 + } + } + + oldctrl = ctrl; + ctrl = m_vSqitItemList.at(idx).m_code; + + blockNum = 0; blockTimes = 0; blockjumps = 0; + elockNum = 0; elockTimes = 0; elockjumps = 0; + cutflag = 0; + + if ((ctrl == DATA_SEWING || + ctrl == DATA_SECF_SEW || + ctrl == DATA_SYNCSEW)) + { + if (oldctrl != ctrl) + { + blockNum = paraBLockNum; // 起始锁针针数 + blockTimes = paraBLockTimes; // 起始锁针次数 + blockjumps = paraBLockJumps; // 起针跳过针数 + if ((blockTimes%2) != 0) // 使回针成为偶数 + { + blockTimes++; + blockjumps += blockNum; + } + } + + if ( idx+1 >= sqrtNum || // 边界条件 数据最后 + + (ctrl == DATA_SYNCSEW && + (m_vSqitItemList[idx+1].m_code == DATA_SEWING + || m_vSqitItemList[idx+1].m_code == DATA_SECF_SEW)) || // 两个机头变成一个机头时候需要添加剪线 这个剪线的具体执行要下位机自己判断 + + ((ctrl == DATA_SEWING || ctrl == DATA_SYNCSEW || ctrl == DATA_SECF_SEW) && // 一组线段的后面添加剪线 + (m_vSqitItemList[idx+1].m_code == DATA_OFFSET || + m_vSqitItemList[idx+1].m_code == DATA_SECF_OFST || + m_vSqitItemList[idx+1].m_code == DATA_SYNCOFST)) || + + fabs(m_vSqitItemList.at(idx+1).m_begx - m_vSqitItemList.at(idx).m_endx) > 1 || // 上一条线的尾部和和下一条的头部不相连 边界条件 基本不会触发 + fabs(m_vSqitItemList.at(idx+1).m_begy - m_vSqitItemList.at(idx).m_endy) > 1 || // 上一条线的尾部和和下一条的头部不相连 边界条件 基本不会触发 + 0 ) + { + elockNum = paraELockNum; // 结束锁针针数 + elockTimes = paraELockTimes; // 结束锁针次数 + elockjumps = paraELockJumps; // 结束跳过针数 + if ((elockTimes%2) != 0) // 使回针成为偶数 + { + elockTimes++; + elockjumps += elockNum; + } + + cutflag = 1; + } + } + + threex[0] = m_vSqitItemList.at(idx).m_begx; + threey[0] = m_vSqitItemList.at(idx).m_begy; + threex[1] = m_vSqitItemList.at(idx).m_midx; + threey[1] = m_vSqitItemList.at(idx).m_midy; + threex[2] = m_vSqitItemList.at(idx).m_endx; + threey[2] = m_vSqitItemList.at(idx).m_endy; + + stepNumber = CalcCurve(threex, threey, NULL, NULL, NULL, stepSize, NULL, ctrl); + curtNumber = stepNumber + blockNum*blockTimes + elockNum*elockTimes; + + // qDebug("stepNumber = %d, cur totalNumber=%d:\r\n", stepNumber, curtNumber); + + if (totalNumber + curtNumber >= maxitemnum) + { + rslt = -1; + break; + } + pData = pSteps + (blockNum*blockTimes); + + n = CalcCurve(threex, threey, &actx, &acty, &actr, stepSize, pData, ctrl); + if (n != stepNumber) + { + // qDebug("create number =%d, is not equal to stepNumber=%d:\r\n", n, stepNumber); + } + + //------------------ + // 倒序添加起针锁针 +#if (0) + // 起始锁针信息 + printf("before add lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + pTemp = pData - 1; + k = blockTimes*blockNum; + for (i = 0; i < blockTimes; i++) + { + if (i%2 == 0) // 奇数锁针 + { + // printf("ji shu:\r\n"); + for (j = 0; j < blockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + k--; + if (k < blockjumps) // 跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp--; + } + } + else // 偶数锁针 + { + // printf("ou shu:\r\n"); + for (j = blockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + + k--; + if (k < blockjumps) // 跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp--; + } + } + } + // 正向扫描,修正起针回针中的dr + k = blockTimes*blockNum; + pTemp = pData - k; + if(blockTimes != 0 ) + { + for (i = 0; i <= blockTimes; i++) // 跳过第一次锁针(偶数),且 + { + if (i%2 == 0) // 偶数锁针 + { + if (i == 0) // 第一针, 这里不做处理,后面添加单独运动dr的offset + { + } + else + { + pTemp->dr = 0; + } + pTemp += blockNum; + } + else // 奇数锁针 + { + pTemp += blockNum - 1 ; + pTemp->dr = 0; + pTemp++; + } + } + } +#if (0) + // 结束锁针信息 + printf("after add begin lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + //------------------ + // 顺序添加末针锁针 + pTemp = pData + stepNumber; + k = 0; + for (i = 0; i < elockTimes; i++) + { + if (i%2 == 0) // 奇数锁针 + { + for (j = 0; j < elockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + + k++; + if (k > elockTimes*elockNum - elockjumps) // 结束跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp++; + } + } + else + { + for (j = elockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + k++; + if (k > elockTimes*elockNum - elockjumps) // 结束跳过计数器 + { + pTemp->ctrl = DATA_OFFSET; // 转换为offset + } + else + { + attr = pTemp->attr; + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + } + pTemp++; + } + } + } + +#if (0) + printf("after add end lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + //------------------ + + stepNumber = curtNumber; + + if (cutflag != 0) // 缝纫针步添加剪线码 + { + // 添加剪线码 + pSteps[stepNumber].ctrl = DATA_CUTTRD; + pSteps[stepNumber].attr = 0; + pSteps[stepNumber].dx = 0; + pSteps[stepNumber].dy = 0; + pSteps[stepNumber].dr = 0; + stepNumber++; + } + +#if (0) + printf("after jump lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + + pSteps += stepNumber; + totalNumber += stepNumber; + begflag = 1; + } // end of for(idx...... + + //------------------ + // 最后一针添加结束码 + dataItemArray[totalNumber].ctrl = DATA_END; + dataItemArray[totalNumber].attr = 0; + dataItemArray[totalNumber].dx = 0; + dataItemArray[totalNumber].dy = 0; + dataItemArray[totalNumber].dr = 0; + + totalNumber++; + if (rslt != 0) + { + qDebug("no enough item mem"); + } + +#if (0) + printf("after calc, begx=%d, begy=%d, stepNumber=%d\r\n", begx, begy, totalNumber); +#endif + +#if (1) + // 剪线码移到缝纫数据之后 + pData = dataItemArray; // 源 + begflag = 0; + + for (i = 0; i < totalNumber; i++) + { + if ((pData->ctrl == DATA_SEWING || pData->ctrl == DATA_SYNCSEW)) + { + begflag = 1; + } + else if (pData->ctrl == DATA_OFFSET) + { + if (begflag == 1) + { + pSteps = pData; + begflag = 2; + } + else if (begflag != 2) + { + begflag = 0; + } + } + else if (pData->ctrl == DATA_CUTTRD) + { + if (begflag == 2) + { + // 交换 pSteps 和 pData + DataItem tmpItem; + memcpy(&tmpItem, pData, sizeof(DataItem)); + memcpy(pData, pSteps, sizeof(DataItem)); + memcpy(pSteps, &tmpItem, sizeof(DataItem)); + } + begflag = 0; + } + else + { + begflag = 0; + } + pData++; + } + +#endif + pData = dataItemArray; // 源 + pSteps = pData; // 目标 + // 扫描生成数据,确定起点坐标,合并offset数据 + // 起点坐标 + begr = pData[0].dr; // 第一个针步,dr是从0开始的变化量 + pData[0].dr = 0; // 设置第一个针步的变化量为0 + + i = 0; +#if (0) + for (i = 0; i < totalNumber; i++) + { + if (pData->ctrl != DATA_OFFSET) // 起始的offset合并到起点坐标 + { + break; + } + + begx += pData->dx; + begy += pData->dy; + begr += pData->dr; // 改变起针位置 + pData++; // 源后移 + } +#endif + + begflag = 0; + actr = begr; +#if (0) + int offset_dr; + + // 继续扫描生成数据,合并offset数据 + for (i = i, j = 0; i < totalNumber; i++) + { + if (pData->ctrl == DATA_OFFSET) + { + if (begflag == 0) + { + // 初始化offset计数 + threex[0] = 0; + threey[0] = 0; + threex[1] = 0; + threey[1] = 0; + threex[2] = 0; + threey[2] = 0; + offset_dr = 0; + begflag = 1; + } + + threex[2] += pData->dx; + threey[2] += pData->dy; + offset_dr += pData->dr; + } + else + { + if (begflag != 0 && pData->ctrl != DATA_END) + { + // 重新插入偏移数据 + actx = 0; + acty = 0; + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, S16_MAX*3/5, pSteps, DATA_OFFSET); + pSteps->dr = offset_dr ; + + pSteps += stepNumber; + j += stepNumber; + begflag = 0; + } + if (pSteps != pData) + { + memcpy(pSteps, pData, sizeof(DataItem)); + } + j++; + actr += pSteps->dr; + pSteps++; + } + + pData++; + } + + totalNumber = j; +#endif + +#if (0) + printf("before write begx=%d, begy=%d, stepNumber=%d\r\n", begx, begy, totalNumber); +#endif + +#ifdef used_mac_DHQ // 1 插入小的数据 0 不插入小的数据 + + DataItem * cp_dataItemArray = new DataItem[totalNumber]; + + memcpy( cp_dataItemArray , dataItemArray , sizeof( DataItem )*totalNumber); + + j = 0 ; + for (int var = 0; var < totalNumber; ++var) + { + if((var + 1) > totalNumber) + { + break; + } + else if( + (cp_dataItemArray[var].ctrl == cp_dataItemArray[var + 1].ctrl) + && + ((cp_dataItemArray[var].ctrl == DATA_SEWING)|| + (cp_dataItemArray[var].ctrl == DATA_SECF_SEW)|| + (cp_dataItemArray[var].ctrl == DATA_SYNCSEW) + ) + && + (fabs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len) > + 1.8 * m_rvsf_info.i_dense_step) + ) + { + DataItem temp ; +#if 1 + memset( &temp , 0 , sizeof (DataItem )); + + int len = cp_dataItemArray[var].len ; + + if( cp_dataItemArray[ var ].len > cp_dataItemArray[ var + 1 ].len ) + { + len = cp_dataItemArray[ var + 1 ].len ; + } + else if( cp_dataItemArray[var].len < cp_dataItemArray[var + 1].len) + { + len = cp_dataItemArray[ var ].len ; + } + + if( abs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len ) > len*0.3 ) + { + memcpy( &(temp) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + temp.attr |= ATTR_RESEW; + memcpy( &(dataItemArray[j]) , &(temp) , sizeof( DataItem )); + j++; + } + else if( abs( cp_dataItemArray[var].len - cp_dataItemArray[var + 1 ].len ) > len*0.3 ) + { + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + j++; + var++; + memcpy( &(temp) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + temp.attr |= ATTR_RESEW; + memcpy( &(dataItemArray[j]) , &(temp) , sizeof( DataItem )); + j++; + } +#endif + +#if 0 + + if( cp_dataItemArray[var].len > cp_dataItemArray[var + 1 ].len) + { + + //两个索引都退两个 + var -= 2; + j -= 2; + + //复制第一个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.attr |= ATTR_RESEW; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + var++; + + //复制第二个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + var++; + } + else if( cp_dataItemArray[var + 1].len > cp_dataItemArray[var].len) + { + + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + var++; + j++ ; + + //复制第一个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.attr |= ATTR_RESEW; + + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[var]) , &temp, sizeof( DataItem )); + j++ ; + var++; + + //复制第二个针步 + memcpy( &temp , &(cp_dataItemArray[var]) , sizeof( DataItem )); + + temp.dx = temp.dx / 2 ; + temp.dy = temp.dy / 2 ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + + temp.dx = cp_dataItemArray[var].dx - temp.dx ; + temp.dy = cp_dataItemArray[var].dy - temp.dy ; + temp.len = sqrt( temp.dx * temp.dx* 1.0 + temp.dy *temp.dy * 1.0); + memcpy( &(dataItemArray[j]) , &temp, sizeof( DataItem )); + j++ ; + var++; + } +#endif + } + else + { + memcpy( &(dataItemArray[j]) , &(cp_dataItemArray[var]) , sizeof( DataItem )); + j++ ; + } + } + delete [] cp_dataItemArray; + totalNumber = j; +#endif + +#if 0 + QList < DataItem > i_list ; + DataItem i_item ; + + for( int count = 0 ; count < (totalNumber); count++) + { + memset( & i_item , 0 , sizeof ( DataItem )); + memcpy( & i_item , & (dataItemArray[ count ]) , sizeof ( DataItem )); + + i_list.append(i_item); + + if( (count + 1) == totalNumber ) + { + break; + } + + if( + ( dataItemArray[count].ctrl == DATA_OFFSET ) + && + ( + ( dataItemArray[count + 1 ].ctrl == DATA_RKNIFE ) + ||( dataItemArray[count + 1 ].ctrl == DATA_SKNIFE ) + ) + ) + { + i_item.ctrl = DATA_OFFSET ; +// i_item.ctrl = dataItemArray[count + 1 ].ctrl ; + i_item.attr = 0 ; + i_item.dx = 0 ; + i_item.dy = 0 ; + i_item.dr = dataItemArray[i + 1 ].dr ; + i_item.len = 0 ; + + i_list.append(i_item); + dataItemArray[count + 1 ].dr = 0 ; + } + } + + totalNumber = i_list.size() ; + for( int count = 0 ; count < totalNumber ; count++) + { + memcpy( & (dataItemArray[ count ]) , & (i_list[count]) , sizeof ( DataItem )); + } + + i_list.clear(); + +#endif + + // dataItemArray + + for( int i = 0 ; i < (totalNumber -1); i++) + { + if( + ( dataItemArray[i].ctrl == DATA_OFFSET ) + && + ( + ( dataItemArray[i + 1 ].ctrl == DATA_RKNIFE ) + ||( dataItemArray[i + 1 ].ctrl == DATA_SKNIFE ) + ||( dataItemArray[i + 1 ].ctrl == DATA_DRAWING ) + ) + ) + { + int nSum = dataItemArray[i ].dr + dataItemArray[i + 1 ].dr; + + if(abs(nSum)> PI*RADIAN_ACCURACY) + { + if(nSum >0) + { + nSum -= 2*PI*RADIAN_ACCURACY; + } + else + { + nSum += 2*PI*RADIAN_ACCURACY; + } + } + + dataItemArray[i ].dr = nSum; + + dataItemArray[i + 1 ].dr = 0 ; + } + } + + // 写文件头 + DataFileHead fileHead; // 数据文件头描述 + memset(&fileHead, 0, sizeof(DataFileHead)); + + m_filename = "test.plt"; + QByteArray ba = m_filename.toLatin1(); // ISO-8859-1 文件名称 + int cpsize = ba.size(); + if (cpsize > 32) + { + cpsize = 32; + } + + + memcpy(fileHead.fileName, (char*)ba.data(), cpsize); + + fileHead.dataSize = totalNumber*sizeof(DataItem); // 文件长度 + fileHead.itemNums = totalNumber; // 有效针数 + fileHead.bytesPerItem = sizeof(DataItem); // 每针占的字节数 + fileHead.bytesPerBlk = 1024; // 文件内容划分块大小 + + fileHead.dataChecksum = CalcCheckSum32((u8*)(dataItemArray), totalNumber*sizeof(DataItem)); // 花样数据累加校验和 + fileHead.checkCrc = CalcCrc16((u8*)(&fileHead), 6*sizeof(u32)); // 前6个字段CRC校验 + + + s32 minx, miny, maxx, maxy; + GetDataMinMax(dataItemArray, totalNumber, minx, miny, maxx, maxy); + + + qDebug()<sqrtNum); + printf("\t stepSize = %d\r\n", pSqrt->stepSize); + printf("\t blockNum = %d\r\n", pSqrt->blockNum); + printf("\t blockTimes = %d\r\n", pSqrt->blockTimes); + printf("\t elockNum = %d\r\n", pSqrt->elockNum); + printf("\t elockTimes = %d\r\n", pSqrt->elockTimes); + printf("\t blockjumps = %d\r\n", pSqrt->blockjumps); + printf("\t elockjumps = %d\r\n", pSqrt->elockjumps); +#endif + + sqrtNum = m_vSqitItemList.size(); // 图形个数 + + stepSize = m_para_stepSize; // 分割针步大小 + + begx = m_beginX; + begy = m_beginY; + begr = 0; + + actx = begx; + acty = begy; + actr = 0; + + begflag = 0; + totalNumber = 0; + oldctrl = 0; + cutflag = 0; + + //------------------ + // 生成文件内容 + //int tttt = 0; + for (idx = 0; idx < sqrtNum; idx++) + { + + +#if (0) + printf("\t begx = %f\r\n", pSqrt->sqrtItem[idx].begx); + printf("\t begy = %f\r\n", pSqrt->sqrtItem[idx].begy); + printf("\t endx = %f\r\n", pSqrt->sqrtItem[idx].endx); + printf("\t endy = %f\r\n", pSqrt->sqrtItem[idx].endy); + printf("\t midx = %f\r\n", pSqrt->sqrtItem[idx].midx); + printf("\t midy = %f\r\n", pSqrt->sqrtItem[idx].midy); +#endif + if (begflag != 0) + { + if (m_vSqitItemList.at(idx).m_begx != m_vSqitItemList.at(idx-1).m_endx || + m_vSqitItemList.at(idx).m_begy != m_vSqitItemList.at(idx-1).m_endy || + 0 ) + { + // 自动插入偏移数据 + threex[0] = m_vSqitItemList.at(idx-1).m_endx; + threey[0] = m_vSqitItemList.at(idx-1).m_endy; + threex[1] = m_vSqitItemList.at(idx).m_begx; + threey[1] = m_vSqitItemList.at(idx).m_begy; + threex[2] = m_vSqitItemList.at(idx).m_begx; + threey[2] = m_vSqitItemList.at(idx).m_begy; // 三点共线,作为直线 + + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, S16_MAX/2, pSteps, DATA_OFFSET); + pSteps += stepNumber; + totalNumber += stepNumber; + + } + } + + oldctrl = ctrl; + //ctrl = m_vSqitItemList.at(idx).m_sqrttype;//20200211 + ctrl = m_vSqitItemList.at(idx).m_code; + + blockNum = 0; + blockTimes = 0; + blockjumps = 0; + + elockNum = 0; + elockTimes = 0; + elockjumps = 0; + cutflag = 0; + + if ((ctrl == DATA_SEWING || ctrl == DATA_SYNCSEW)) + { + if (oldctrl != ctrl) + { + blockNum = m_para_blockNum; // 起始锁针针数 + blockTimes = m_para_blockTimes; // 起始锁针次数 + blockjumps = m_para_blockjumps; // 起针跳过针数 + + if (blockTimes > 0) + { + if (blockjumps > blockTimes*blockNum) + { + blockTimes = 0; + blockNum = 0; + blockjumps = 0; + } + } + else + { + blockTimes = 0; + blockNum = 0; + blockjumps = 0; + } + } + + if (idx+1 >= sqrtNum || m_vSqitItemList.at(idx+1).m_code != ctrl) + { + elockNum = m_para_blockNum; // 结束锁针针数 + elockTimes = m_para_blockTimes; // 结束锁针次数 + elockjumps = m_para_blockjumps; // 结束跳过针数 + cutflag = 1; + if (elockTimes > 0) + { + if (elockjumps > elockTimes*elockNum) + { + elockTimes = 0; + elockNum = 0; + elockjumps = 0; + } + } + else + { + elockTimes = 0; + elockNum = 0; + elockjumps = 0; + } + } + } + + threex[0] = m_vSqitItemList.at(idx).m_begx; + threey[0] = m_vSqitItemList.at(idx).m_begy; + threex[1] = m_vSqitItemList.at(idx).m_midx; + threey[1] = m_vSqitItemList.at(idx).m_midy; + threex[2] = m_vSqitItemList.at(idx).m_endx; + threey[2] = m_vSqitItemList.at(idx).m_endy; + + stepNumber = CalcCurve(threex, threey, &actx, &acty, &actr, stepSize, NULL, ctrl); + curtNumber = stepNumber + blockNum*blockTimes + elockNum*elockTimes - blockjumps - elockjumps; + + // printf("stepNumber = %d, cur totalNumber=%d:\r\n", stepNumber, curtNumber); + + pData = pSteps + (blockNum*blockTimes) - blockjumps; + n = CalcCurve(threex, threey, &actx, &acty, &actr, stepSize, pData, ctrl); + if (n != stepNumber) + { + // printf("create number =%d, is not equal to stepNumber=%d:\r\n", n, stepNumber); + } + + + if (begflag == 0) + { + begr = pData->dr; + pData->dr = 0; + } + +#if (0) + // 起始锁针信息 + printf("before add lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + + // 倒序添加起针锁针 + pTemp = pData - 1; + k = blockTimes*blockNum; + for (i = 0; i < blockTimes; i++) + { + if (k < blockjumps) // 跳过计数器 + { + break; + } + k--; + if (i%2 == 0) // 奇数锁针 + { + // printf("ji shu:\r\n"); + for (j = 0; j < blockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + attr = pTemp->attr; + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + + if (begflag == 0) + { + begx += pTemp->dx; + begy += pTemp->dy; + } + pTemp--; + } + } + else // 偶数锁针 + { + // printf("ou shu:\r\n"); + for (j = blockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[j]), sizeof(DataItem)); + pTemp->attr |= ATTR_RESEW; // 回针标志 + + if (begflag == 0) + { + begx += pTemp->dx; + begy += pTemp->dy; + } + pTemp--; + } + } + } + +#if (0) + // 结束锁针信息 + printf("after add begin lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + + // 顺序添加末针锁针 + pTemp = pData + stepNumber; + k = 0; + for (i = 0; i < elockTimes; i++) + { + k++; + if (k > elockTimes*elockNum - elockjumps) // 结束跳过计数器 + { + break; + } + if (i%2 == 0) // 奇数锁针 + { + for (j = 0; j < elockNum; j++) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + attr = pTemp->attr; + pTemp->dx *= -1; + pTemp->dy *= -1; // 方向取反 + pTemp->dr *= -1; // 方向取反 + attr |= ATTR_RESEW; // 回针标志 + pTemp->attr = attr; + pTemp++; + } + } + else + { + for (j = elockNum-1; j >= 0; j--) + { + // 拷贝针步 + memcpy(pTemp, &(pData[stepNumber-1-j]), sizeof(DataItem)); + pTemp->attr |= ATTR_RESEW; // 回针标志 + pTemp++; + } + } + } + +#if (0) + printf("after add end lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + + stepNumber = curtNumber; + + if (cutflag != 0) // 缝纫针步添加剪线码 + { + // 添加剪线码 + pSteps[stepNumber].ctrl = DATA_CUTTRD; + pSteps[stepNumber].attr = 0; + pSteps[stepNumber].dx = 0; + pSteps[stepNumber].dy = 0; + stepNumber++; + } + +#if (0) + printf("after jump lock:\r\n"); + for (i = 0; i < curtNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pSteps[i].ctrl, pSteps[i].attr, pSteps[i].dx, pSteps[i].dy); + } +#endif + + pSteps += stepNumber; + totalNumber += stepNumber; + begflag = 1; + + } // end of for(idx...... + + // 最后一针添加结束码 + dataItemArray[totalNumber].ctrl = DATA_END; + dataItemArray[totalNumber].attr = 0; + dataItemArray[totalNumber].dx = 0; + dataItemArray[totalNumber].dy = 0; + totalNumber++; + + // 合并角度到前面的offset + DataItem * pTDItem; + pTDItem = new DataItem[totalNumber]; + + memcpy(pTDItem, dataItemArray, sizeof(DataItem)*totalNumber); + + for (i = 0, j = 0; i < totalNumber; i++) + { + if (i != 0 && pTDItem[i-1].ctrl == DATA_OFFSET && pTDItem[i].ctrl != DATA_OFFSET && pTDItem[i].dr != 0) + { + memset(&(dataItemArray[j]), 0, sizeof(DataItem)); + dataItemArray[j].ctrl = DATA_OFFSET; + dataItemArray[j].dr = pTDItem[i].dr; + j++; + pTDItem[i].dr = 0; + } + + memcpy(&(dataItemArray[j]), &(pTDItem[i]), sizeof(DataItem)); + j++; + } + totalNumber = j; + delete []pTDItem; + pTDItem = NULL; + + // 写文件头 + // 写文件头 + DataFileHead fileHead; // 数据文件头描述 + memset(&fileHead, 0, sizeof(DataFileHead)); + + m_filename = "test.plt"; + QByteArray ba = m_filename.toLatin1(); // ISO-8859-1 文件名称 + int cpsize = ba.size(); + if (cpsize > 32) + { + cpsize = 32; + } + + + memcpy(fileHead.fileName, (char*)ba.data(), cpsize); + + fileHead.dataSize = totalNumber*sizeof(DataItem); // 文件长度 + fileHead.itemNums = totalNumber; // 有效针数 + fileHead.bytesPerItem = sizeof(DataItem); // 每针占的字节数 + fileHead.bytesPerBlk = 1024; // 文件内容划分块大小 + + fileHead.dataChecksum = CalcCheckSum32((u8*)(dataItemArray), totalNumber*sizeof(DataItem)); // 花样数据累加校验和 + fileHead.checkCrc = CalcCrc16((u8*)(&fileHead), 6*sizeof(u32)); // 前6个字段CRC校验 + + + s32 minx, miny, maxx, maxy; + GetDataMinMax(dataItemArray, totalNumber, minx, miny, maxx, maxy); + +// fileHead.minX = minx - minx + m_beginX; +// fileHead.maxX = maxx - minx + m_beginX; +// fileHead.minY = miny - miny + m_beginY; +// fileHead.maxY = maxy - miny + m_beginY; + + fileHead.minX = minx + m_beginX; + fileHead.maxX = maxx + m_beginX; + fileHead.minY = miny + m_beginY; + fileHead.maxY = maxy + m_beginY; + + fileHead.beginX = m_beginX ; + fileHead.beginY = m_beginY ; + fileHead.beginR = begr; // 起始角度 + + fileHead.anchorX = m_anchorX; + fileHead.anchorY = m_anchorY; // 定位点 + + + + /* ++ begx ++ begy ++ begx ++ begy +*/ +#if (0) + if( 1 ) + { + m_anchorSel = 1 ; // 当文件是 qui 的时候 + + fileHead.beginX = begx; + fileHead.beginY = begy; + } + else if( 0 ) + { + m_anchorSel = 0 ; //当文件是 rvsf 的时候 + + fileHead.beginX = m_rvsf_info.i_Gantry; + fileHead.beginY = m_rvsf_info.i_Head_B; + fileHead.beginR = begr; // 起始点坐标 + + fileHead.beginX2 = m_rvsf_info.i_Gantry; + fileHead.beginY2 = m_rvsf_info.i_Head_A; + fileHead.beginR2 = 0; + + if( fileHead.beginX2 < fileHead.minX) + { + fileHead.minX = fileHead.beginX2; + } + if( fileHead.beginX2 > fileHead.maxX) + { + fileHead.maxX = fileHead.beginX2; + } + if( fileHead.beginY2 < fileHead.minY) + { + fileHead.minY = fileHead.beginY2; + } + if( fileHead.beginY2 > fileHead.maxY) + { + fileHead.maxY = fileHead.beginY2; + } + } + // 定位点选择; 0, 和起点重合; 1,图形的左下角; 2, 图形的右下角; 3, 图形的右上角; 4, 图形的左上角; 5, 图形的中心 + switch (m_anchorSel) + { + case 1: // 1,图形的左下角 + fileHead.anchorX = fileHead.minX; + fileHead.anchorY = fileHead.minY; // 定位点 + break; + case 2: // 2,图形的右下角 + fileHead.anchorX = fileHead.maxX; + fileHead.anchorY = fileHead.minY; // 定位点 + break; + case 3: // 3,图形的右上角 + fileHead.anchorX = fileHead.maxX; + fileHead.anchorY = fileHead.maxY; // 定位点 + break; + case 4: // 4,图形的左上角 + fileHead.anchorX = fileHead.minX; + fileHead.anchorY = fileHead.maxY; // 定位点 + break; + default: + + fileHead.anchorX = fileHead.beginX; + fileHead.anchorY = fileHead.beginY; // 定位点 + + fileHead.anchorX2 = fileHead.beginX2 ; + fileHead.anchorY2 = fileHead.beginY2 ; // 定位点 + + break; + } +#endif + + + +#if (0) + printf("finial write:\r\n"); + for (i = 0; i < stepNumber; i++) + { + printf("DataItem %d:ctrl=0x%x, attr=0x%x, dx=%d, dy=%d\r\n", i, pData[i].ctrl, pData[i].attr, pData[i].dx, pData[i].dy); + } +#endif + // 拷贝数据 + ds16Ary.resize(sizeof(DataFileHead)+totalNumber*sizeof(DataItem)); + memcpy (ds16Ary.data(), &fileHead, sizeof(DataFileHead)); + memcpy (&m_fileHead, &fileHead, sizeof(DataFileHead)); + memcpy (ds16Ary.data() + sizeof(DataFileHead), dataItemArray, totalNumber*sizeof(DataItem)); + + delete []dataItemArray; + + + return 0; + + + + +} + +#endif + + +int GetDataMinMax(DataItem * pData, int nums, s32 & minx, s32 & miny, s32 & maxx, s32 & maxy) +{ + s32 actx, acty; + + minx = miny = INT_MAX; + maxx = maxy = INT_MIN; + actx = acty = 0; + + if (pData == NULL) + { + return -1; + } + + int i; + for (i = 0; i < nums; i++) + { + if ( pData->ctrl == DATA_END || // 结束码 + pData->ctrl == DATA_NULL || // 文件结束 + 0 ) + { + break; + } + + if ( pData->ctrl == DATA_PAUSE || // 暂停功能码 + pData->ctrl == DATA_CHGND || // 换针功能码(换色) + pData->ctrl == DATA_CUTTRD || // 剪线功能码 + pData->ctrl == DATA_ANGLE || // 拐点功能码 + 0 ) + { + pData++; + continue; + } + + actx += pData->dx; + acty += pData->dy; + + if (actx < minx) + { + minx = actx; + } + if (actx > maxx) + { + maxx = actx; + } + + if (acty < miny) + { + miny = acty; + } + if (acty > maxy) + { + maxy = acty; + } + pData++; + } + return 0; +} + +int VectorSqrt::CreateDs8FromDs16(const QByteArray & ds16Ary, QByteArray & ds8Ary) +{ + int rslt = 0; + int ds16size = ds16Ary.size(); + ds8Ary.clear(); + + if (ds16size <= (int)sizeof(DataFileHead) || + ((ds16size - sizeof(DataFileHead))%sizeof(DataItem) != 0) ) + { + rslt = -1; + return rslt; + } + + const char * ds16buff = ds16Ary.data(); + DataFileHead * pDs16FileHead = (DataFileHead *)ds16buff; + DataItem * ds16Array = (DataItem *)(ds16buff+sizeof(DataFileHead)); + int itemnum = (ds16size - sizeof(DataFileHead)) / sizeof(DataItem); + + int ds8size = sizeof(DataFileHead) + itemnum * sizeof(Ds8Item); + + char * ds8buff = new char[ds8size]; + DataFileHead * pDs8FileHead = (DataFileHead *)ds8buff; + Ds8Item * ds8Array = (Ds8Item *)(ds8buff+sizeof(DataFileHead)); + + DataItem * pDs16Ptr = ds16Array; + Ds8Item * pDs8Ptr = ds8Array; + int i; + for (i = 0; i < itemnum; i++) + { + pDs8Ptr->ctrl = pDs16Ptr->ctrl; + pDs8Ptr->attr = pDs16Ptr->attr; + pDs8Ptr->dx = pDs16Ptr->dx; + pDs8Ptr->dy = pDs16Ptr->dy; + pDs8Ptr->dr = pDs16Ptr->dr; + pDs8Ptr++; + pDs16Ptr++; + } + + memcpy(pDs8FileHead, pDs16FileHead, sizeof(DataFileHead)); + + pDs8FileHead->dataSize = itemnum*sizeof(Ds8Item); // 文件长度 + pDs8FileHead->itemNums = itemnum; // 有效针数 + pDs8FileHead->bytesPerItem = sizeof(Ds8Item); // 每针占的字节数 + pDs8FileHead->bytesPerBlk = 1024; // 文件内容划分块大小 + + pDs8FileHead->dataChecksum = CalcCheckSum32((u8*)(ds8Array), itemnum*sizeof(Ds8Item)); // 花样数据累加校验和 + pDs8FileHead->checkCrc = CalcCrc16((u8*)(pDs8FileHead), 6*sizeof(u32)); // 前6个字段CRC校验 + + // 其余字段不变...... + + // 拷贝数据 + ds8Ary.resize(ds8size); + memcpy(ds8Ary.data(), ds8buff, ds8size); + delete []ds8buff; + + return rslt; +} + +int VectorSqrt::CreateDs4FromSqrt(QByteArray & ds4Ary) +{ + int rslt = 0; + ds4Ary.clear(); + + return rslt; +} + +int VectorSqrt::CreateDs2FromDs4(const QByteArray & ds4Ary, QByteArray & ds2Ary) +{ + int rslt = 0; + + int ds4size = ds4Ary.size(); + ds2Ary.clear(); + + if (ds4size <= (int)sizeof(DataFileHead) || + ((ds4size - sizeof(DataFileHead))%sizeof(Ds4Item) != 0) ) + { + rslt = -1; + return rslt; + } + + const char * ds4buff = ds4Ary.data(); + DataFileHead * pDs4FileHead = (DataFileHead *)ds4buff; + Ds4Item * ds4Array = (Ds4Item *)(ds4buff+sizeof(DataFileHead)); + int itemnum = (ds4size - sizeof(DataFileHead)) / sizeof(Ds4Item); + + int ds2size = sizeof(DataFileHead) + itemnum * sizeof(Ds2Item); + + char * ds2buff = new char[ds2size]; + DataFileHead * pDs2FileHead = (DataFileHead *)ds2buff; + Ds2Item * ds2Array = (Ds2Item *)(ds2buff+sizeof(DataFileHead)); + + Ds4Item * pDs4Ptr = ds4Array; + Ds2Item * pDs2Ptr = ds2Array; + int i; + u8 cdx, cdy; + u8 yux, yuy; + yux = yuy = 0; + for (i = 0; i < itemnum; i++) + { + if ( pDs4Ptr->ctrl == DATA_SEWING || + pDs4Ptr->ctrl == DATA_OFFSET || + 0 ) + { + cdx = pDs4Ptr->dx; + cdx += yux; + yux = cdx & 0x01; + cdy = pDs4Ptr->dy; + cdy += yuy; + yuy = cdy & 0x01; + if (pDs4Ptr->ctrl == DATA_SEWING) + { + cdx &= 0xFE; + cdy &= 0xFE; // 0 0 缝纫数据,数据范围从-128 -- +126, 只有偶数可用(精度0.2mm),单位0.1mm + } + else if (pDs4Ptr->ctrl == DATA_OFFSET) + { + cdx &= 0xFE; + cdy |= 0x01; // 0 1 空走数据,数据范围从-128 -- +126, 只有偶数可用(精度0.2mm),单位0.1mm + } + } + else + { + cdx = pDs4Ptr->ctrl; + cdx <<= 1; + cdx |= 0x01; + cdy = 0x01; // 1 1 控制数据,数据位定义为控制码和参数 cdx.7--cdx.1 控制码 cdy.7--cyd.1 为参数 + } + + pDs2Ptr->cdx = cdx; + pDs2Ptr->cdy = cdy; + + pDs2Ptr++; + pDs4Ptr++; + } + + memcpy(pDs2FileHead, pDs4FileHead, sizeof(DataFileHead)); + + pDs2FileHead->dataSize = itemnum*sizeof(Ds2Item); // 文件长度 + pDs2FileHead->itemNums = itemnum; // 有效针数 + pDs2FileHead->bytesPerItem = sizeof(Ds2Item); // 每针占的字节数 + pDs2FileHead->bytesPerBlk = 1024; // 文件内容划分块大小 + + pDs2FileHead->dataChecksum = CalcCheckSum32((u8*)(ds2Array), itemnum*sizeof(Ds2Item)); // 花样数据累加校验和 + pDs2FileHead->checkCrc = CalcCrc16((u8*)(pDs2FileHead), 6*sizeof(u32)); // 前6个字段CRC校验 + + // 其余字段不变...... + + // 拷贝数据 + ds2Ary.resize(ds2size); + memcpy(ds2Ary.data(), ds2buff, ds2size); + + delete []ds2buff; + + return rslt; +} + + +//--------------------------------------------------------------------------------------------------------- +// 生成数据文件的算法 + +#if (1) + +// 分割直线 +int CalcLine(double x0, double y0, double x1, double y1, int * pactx, int * pacty, int stepSize, DataItem * pData, u8 type, s16 dr) +{ + double length, tmp, len; + double stepx, stepy; + double sx, sy; + double xlk; + int i, count; + int actx, acty; + s32 sdx, sdy; + u8 attr; + + attr = 0; + + if(x0 == x1 && y0 == y1) + { + return 0; + } + + if(x0 > x1) + { + sx = -1.0; // x反向 + } + else + { + sx = 1.0; + } + + if(y0 > y1) + { + sy = -1.0; // y反向 + } + else + { + sy = 1.0; + } + + // 开始分割针步 + length = sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)); + tmp = length/stepSize; // 实际针步数 + count = (int)(tmp); // 最少整针步数 + + if (tmp - count >= 0.5) + { + count += 1; + // printf("count++=%d\r\n", count); + } + + if (count == 0 && length > 0) // 短直线 + { + count = 1; + } + + if (pData == NULL) + { + return count; + } + + actx = *pactx; + acty = *pacty; + + if (x1 != x0 && y1 == y0) // 横直线 + { + // printf("H Line: \r\n"); + sdy = 0; + for (i = 0; i < count; i++) + { + tmp = ((i+1)*(length)/count)*sx + x0; // 实际坐标 + + stepx = (tmp - actx); + sdx = (s32)(stepx+0.5*sx); + + pData[i].ctrl = type; + pData[i].attr = attr; + pData[i].dx = sdx; + pData[i].dy = sdy; + pData[i].dr = 0; + + len = sqrt(1.0*sdx*sdx + 1.0*sdy*sdy); + pData[i].len = (u16)(len+0.9); + + actx += sdx; + // acty += sdy; + } + } + else if (x1 == x0 && y1 != y0) // 竖直线 + { + // printf("v Line: \r\n"); + + sdx = 0; + for (i = 0; i < count; i++) + { + tmp = ((i+1)*(length)/count)*sy + y0; // 实际针步 + + stepy = (tmp - acty); + sdy = (s32)(stepy+0.5*sy); + + pData[i].ctrl = type; + pData[i].attr = attr; + pData[i].dx = sdx; + pData[i].dy = sdy; + pData[i].dr = 0; + + len = sqrt(1.0*sdx*sdx + 1.0*sdy*sdy); + pData[i].len = (u16)(len+0.9); + // actx += sdx; + acty += sdy; + } + } + else if(x1 != x0 && y1 != y0) // 任意斜线 + { + // printf("any Line: k=%f\r\n", xlk); + + // 斜率 + xlk = (y1-y0)/(x1-x0); + for (i = 0; i < count; i++) + { + tmp = ((i+1)*(length)/count); // 实际针步 + + stepx = fabs(tmp*cos(atan(xlk)))*sx + x0 - actx; + stepy = fabs(tmp*sin(atan(xlk)))*sy + y0 - acty; + + sdx = (s32)(stepx+0.5*sx); + sdy = (s32)(stepy+0.5*sy); + + pData[i].ctrl = type; + pData[i].attr = attr; + pData[i].dx = sdx; + pData[i].dy = sdy; + pData[i].dr = 0; + + len = sqrt(1.0*sdx*sdx + 1.0*sdy*sdy); + pData[i].len = (u16)(len+0.9); + + actx += sdx; + acty += sdy; + } + } + pData[0].dr = dr; // 第一段数据添加r变化量 + + *pactx = actx; + *pacty = acty; + + return count; +} + +//--------------------------------------------------------------------------------------------------------- +// 圆弧 + +// 旋转坐标值 +void Rotatec(double xin, double yin, double * px, double * py, double angle) +{ + *px=xin*cos(angle)-yin*sin(angle); + *py=xin*sin(angle)+yin*cos(angle); +} + +// 根据坐标确定增加方向 +int ArcDir(const double x[], const double y[]) +{ + double k; + if(x[1] > x[0]) + { + k = (y[1] - y[0]) / (x[1]-x[0]); + if (y[2] < (k*(x[2]-x[1]) + y[1])) + { + return -1; + } + else + { + return 1; + } + } + else if (x[1] < x[0]) + { + k = (y[1] - y[0]) / (x[1] - x[0]); + if (y[2] < (k * (x[2]-x[1]) + y[1])) + { + return 1; + } + else + { + return -1; + } + } + else if ( (x[2]>x[1] && y[1]x[1] && y[1]>y[0]) || (x[2]y[1]) ) + { + return -1; + } + else + { + printf("1. what's this case?\r\n"); + return 0; + } +} + +// 三点共线 +int IsThreePointOnALine(const double threex[], const double threey[]) +{ + double k0,k1,k2; + + if ((fabs(threex[0]-threex[1]) < 1e-6) && + (fabs(threex[0]-threex[2]) < 1e-6) && + (fabs(threex[2]-threex[1]) < 1e-6) && + (fabs(threey[0]-threey[1]) < 1e-6) && + (fabs(threey[0]-threey[2]) < 1e-6) && + (fabs(threey[2]-threey[1]) < 1e-6) && + 1 ) + { + // printf("1.IsThreePointOnALine\r\n"); + return 1; + } + else if ( ((fabs(threex[0]-threex[1]) < 1e-6) && (fabs(threey[0]-threey[1]) < 1e-6)) || + ((fabs(threex[0]-threex[2]) < 1e-6) && (fabs(threey[0]-threey[2]) < 1e-6)) || + ((fabs(threex[2]-threex[1]) < 1e-6) && (fabs(threey[2]-threey[1]) < 1e-6)) || + 0 ) + { + // printf("2.IsThreePointOnALine\r\n"); + return 1; + } + else if ( (fabs(threex[0]-threex[1]) < 1e-6) && + (fabs(threex[0]-threex[2]) < 1e-6) && + (fabs(threex[2]-threex[1]) < 1e-6) && + 1 ) + { + // printf("3.IsThreePointOnALine\r\n"); + return 1; + } + else if ( (fabs(threey[0]-threey[1]) < 1e-6) && + (fabs(threey[0]-threey[2]) < 1e-6) && + (fabs(threey[2]-threey[1]) < 1e-6) && + 1 ) + { + // printf("4.IsThreePointOnALine\r\n"); + return 1; + } + else if ( (fabs(threex[2]-threex[1]) >= 1e-6) && + (fabs(threex[2]-threex[0]) >= 1e-6) && + (fabs(threex[1]-threex[0]) >= 1e-6) && + (fabs(threey[2]-threey[1]) >= 1e-6) && + (fabs(threey[2]-threey[0]) >= 1e-6) && + (fabs(threey[1]-threey[0]) >= 1e-6) && + 1 ) + { + k0 = (threey[2]-threey[1])/(threex[2]-threex[1]); + k1 = (threey[2]-threey[0])/(threex[2]-threex[0]); + k2 = (threey[1]-threey[0])/(threex[1]-threex[0]); + + if(fabs(k0-k1) < 1e-6 && fabs(k1-k2) < 1e-6) + { + // printf("5.IsThreePointOnALine\r\n"); + return 1; + } + else + { + // printf("6.IsThreePointOnALine\r\n"); + return 0; + } + } + else + { + // printf("7.IsThreePointOnALine\r\n"); + return 0; + } +} + +// 得到圆心和半径 +int GetArcCenter(const double x[], const double y[], double * pxc, double * pyc, double * pr) +{ + long double a, b, c, d, e, f; + double xc, yc, r; + + if (IsThreePointOnALine(x, y) == 1) + { + return -1; + } + + a = 2 * (x[1]-x[0]); + b = 2 * (y[1]-y[0]); + c = x[1]*x[1] + y[1]*y[1] - x[0]*x[0] - y[0]*y[0]; + d = 2 * (x[2]-x[1]); + e = 2 * (y[2]-y[1]); + f = x[2]*x[2] + y[2]*y[2] - x[1]*x[1] - y[1]*y[1]; + + xc = (b*f-e*c)/(b*d-e*a); + yc = (d*c-a*f)/(b*d-e*a); + r = sqrt((xc-x[0])*(xc-x[0])+(yc-y[0])*(yc-y[0])); + + *pxc = xc; + *pyc = yc; + *pr = r; + + return 0; +} + +int GetArcRectAndAngle(const double x[], const double y[], double * minx, double * maxx, double * miny, double * maxy, double * startangle, double * aangle) +{ + int rslt; + double cx, cy, r; + double cosf, angle; + rslt = GetArcCenter(x, y, &cx, &cy, &r); + if (rslt == 0) + { + *minx = cx - r; + *maxx = cx + r; + *miny = cy - r; + *maxy = cy + r; + + // 起始点向量和x正向的夹角 + cosf = (x[0]-cx)/r; + if (cosf < -1) + { + cosf = -1; + } + else if (cosf > 1) + { + cosf = 1; + } + angle = acos(cosf); + if (y[0] < cy) + { + angle = 2*PI - angle; + } + *startangle = angle; + + // 计算弦长和圆心角 + double distance2 = ((x[0]-x[2])*(x[0]-x[2])+(y[0]-y[2])*(y[0]-y[2])); // 两点间距离就是弦长 + cosf = ((r*r+r*r)-distance2)/(2*r*r); // cosc = (a*a + b*b - c*c)/2*a*b + if (cosf < -1) + { + cosf = -1; + } + else if (cosf > 1) + { + cosf = 1; + } + + // 圆心角 + angle = acos(cosf); + + // 区分象限和旋转方向 + double k = (x[0]-x[1])*(x[2]-x[1]) + (y[0]-y[1])*(y[2]-y[1]); // 向量 01 和 向量 21 的夹角的余弦的符号-- > 0 小于90度. < 0 大于90度 = 0, 90 度 + if (k > 0) // 夹角小于90度, 说明弧是大于半圆 + { + angle = 2*PI-angle; + } + else // 夹角大于等于90度, 说明弧是小于等于半圆, 不需要处理 + { + } + angle *= ArcDir(x, y); + + *aangle = angle; + } + return rslt; +} + +int GetArcMinMax(const double x[], const double y[], double * pminx, double * pmaxx, double * pminy, double * pmaxy) +{ + double k, xc, yc, r; + int beg = 0; + int mid = 0; + int end = 0; + double minx, miny, maxx, maxy; + + GetArcCenter(x, y, &xc, &yc, &r); + // printf("cx=%f, cy=%f, r=%f\n", xc, yc, r); + // 区分象限和方向 + k = (x[0]-x[1])*(x[2]-x[1]) + (y[0]-y[1])*(y[2]-y[1]); // 向量 01 和 向量 21 的夹角的余弦的符号-- + // > 0 小于90度 + // < 0 大于90度 + // = 0 90 度 + +#ifdef PRTS + printf("k = %f\n", k); + + if (k > 0) // 向量夹角小于90度, 说明弧是大于半圆 + { + printf("angle less then 90d, this arc is more then half cicle\n"); + } + else if (k < 0) // 向量夹角大于90度, 说明弧是小于半圆 + { + printf("angle more then 90d, this arc is less then half cicle\n"); + } + else // 向量夹角等于90度, 说明弧是半圆 + { + printf("angle equal 90d, this arc is equal to half cicle\n"); + } + +#endif + +#ifdef PRTS + printf("x[0]=%f,x[1]=%f,x[2]=%f,xc=%f\n", x[0], x[1], x[2], xc); + printf("y[0]=%f,y[1]=%f,y[2]=%f,yc=%f\n", y[0], y[1], y[2], yc); +#endif + + if (x[0] > xc && y[0] > yc) // 起点在第一象限 + { +#ifdef PRTS + printf("first point in quadrant 1\n"); +#endif + beg = 1; + } + else if (x[0] < xc && y[0] > yc) // 起点在第二象限 + { +#ifdef PRTS + printf("first point in quadrant 2\n"); +#endif + beg = 2; + } + else if (x[0] < xc && y[0] < yc) // 起点在第三象限 + { +#ifdef PRTS + printf("first point in quadrant 3\n"); +#endif + beg = 3; + } + else if (x[0] > xc && y[0] < yc) // 起点在第四象限 + { +#ifdef PRTS + printf("first point in quadrant 4\n"); +#endif + beg = 4; + } + else if (fabs(y[0]-yc) < 1e-6) // 起点在x轴上 + { +#ifdef PRTS + printf("first point on x axes\n"); +#endif + if (x[0] > xc) + { + beg = 5; // x正半轴 + } + else + { + beg = 6; // x负半轴 + } + } + else if (fabs(x[0]-xc) < 1e-6) // 起点在y轴上 + { +#ifdef PRTS + printf("first point on y axes\n"); +#endif + if (y[0] > yc) + { + beg = 7; // y正半轴 + } + else + { + beg = 8; // y正半轴 + } + } + else + { + printf("this is an new selection for first point\n"); + } + + if (x[1] > xc && y[1] > yc) // 中点在第一象限 + { +#ifdef PRTS + printf("second point in quadrant 1\n"); +#endif + mid = 1; + } + else if (x[1] < xc && y[1] > yc) // 中点在第二象限 + { +#ifdef PRTS + printf("second point in quadrant 2\n"); +#endif + mid = 2; + } + else if (x[1] < xc && y[1] < yc) // 中点在第三象限 + { +#ifdef PRTS + printf("second point in quadrant 3\n"); +#endif + mid = 3; + } + else if (x[1] > xc && y[1] < yc) // 中点在第四象限 + { +#ifdef PRTS + printf("second point in quadrant 4\n"); +#endif + mid = 4; + } + else if (fabs(y[1]-yc)<1e-6) // 中点在x轴上 + { +#ifdef PRTS + printf("second point on x axes\n"); +#endif + if (x[1] > xc) {mid = 5;} // x正半轴 + else{ mid = 6; } // x负半轴 + } + else if (fabs(x[1]-xc)<1e-6) // 中点在y轴上 + { +#ifdef PRTS + printf("second point on x axes\n"); +#endif + if (y[1] > yc) // y正半轴 + { + mid = 7; + } + else { mid = 8; } // y负半轴 + } + else + { +#ifdef PRTS + printf("this is an new selection for second point\n"); +#endif + } + + if (x[2] > xc && y[2] > yc) // 终点在第一象限 + { +#ifdef PRTS + printf("third point in quadrant 1\n"); +#endif + end = 1; + } + else if (x[2] < xc && y[2] > yc) // 终点在第二象限 + { +#ifdef PRTS + printf("third point in quadrant 2\n"); +#endif + end = 2; + } + else if (x[2] < xc && y[2] < yc) // 终点在第三象限 + { +#ifdef PRTS + printf("third point in quadrant 3\n"); +#endif + end = 3; + } + else if (x[2] > xc && y[2] < yc) // 终点在第四象限 + { +#ifdef PRTS + printf("third point in quadrant 4\n"); +#endif + end = 4; + } + else if (fabs(y[2]-yc)<1e-6) // 终点在x轴上 + { +#ifdef PRTS + printf("third point on x axes\n"); +#endif + if (x[2] > xc) {end = 5;} // x正半轴 + else{end = 6;} // x负半轴 + } + else if (fabs(x[2]-xc)<1e-6) // 终点在y轴上 + { +#ifdef PRTS + printf("third point on x axes\n"); +#endif + if (y[2] > yc){ end = 7;} // y正半轴 + else{end = 8;} // y负半轴 + } + else + { +#ifdef PRTS + printf("this is an new selection for third point\n"); +#endif + } + +#if 0 + printf("\tx0=%.2f,y0=%.2f\n", x[0], y[0]); + printf("\tx1=%.2f,y1=%.2f\n", x[1], y[1]); + printf("\tx2=%.2f,y2=%.2f\n", x[2], y[2]); + printf("\n\txc=%.2f,yc=%.2f, r=%.2f\n", xc, yc, r); +#endif + + minx = S32_MAX; + maxx = S32_MAX*-1; + miny = S32_MAX; + maxy = S32_MAX*-1; + + switch (beg) + { + case 1: // 起点在第一象限内 + { + switch (end) + { + case 1: // 终点在第一象限内 + case 5: // 终点在x正半轴上 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("1 Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + case 6: // 终点在x负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else // 半弧 + { + printf("2 Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 3: // 终点在第三象限内 + if (mid == 2 || mid == 6 || mid == 7 || + (mid == 1 && x[1] < x[0]) || (mid == 3 && x[1] < x[2])) // 逆时针方向 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (mid == 4 || mid == 5 || mid == 8 || + (mid == 1 && x[1] > x[0]) || (mid == 3 && x[1] > x[2])) // 顺时针方向 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else + { + printf("3. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 4: // 终点在第四象限内 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("4. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + default: + break; + } + + break; + } + case 2: // 起点在第二象限内 + { + switch (end) + { + case 1: // 终点在第一象限内 + case 5: // 终点在x正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else // 半弧 + { + printf("5. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + case 6: // 终点在x负半轴上 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("6. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 3: // 终点在第三象限内 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("7. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 4: // 终点在第四象限内 + if (mid == 3 || mid == 6 || mid == 8 || + (mid == 2 && x[1] < x[0]) || (mid == 4 && x[1] < x[2])) // 逆时针方向 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (mid == 1 || mid == 5 || mid == 7 || + (mid == 2 && x[1] > x[0]) || (mid == 4 && x[1] > x[2])) // 顺时针方向 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else + { + printf("8. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + default: + break; + } + break; + } + case 3: // 起点在第三象限内 + { + switch (end) + { + case 1: // 终点在第一象限内 + if (mid == 4 || mid == 5 || mid == 8 || + (mid == 1 && x[1] > x[0]) || (mid == 3 && x[1] > x[2])) // 逆时针方向 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (mid == 2 || mid == 6 || mid == 7 || + (mid == 1 && x[1] < x[0]) || (mid == 3 && x[1] < x[2])) // 顺时针方向 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else + { + printf("9. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("10. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + case 3: // 终点在第三象限内 + case 6: // 终点在x负半轴上 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("11. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + case 4: // 终点在第四象限内 + case 5: // 终点在x正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("12. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + default: + break; + } + break; + } + case 4: // 起点在第四象限内 + { + switch (end) + { + case 1: // 终点在第一象限内 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("13. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + if (mid == 1 || mid == 5 || mid == 7 || + (mid == 2 && x[1] > x[0]) || (mid == 4 && x[1] > x[2])) // 逆时针方向 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (mid == 3 || mid == 6 || mid == 8 || + (mid == 2 && x[1] < x[0]) || (mid == 4 && x[1] < x[2])) // 顺时针方向 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else + { + printf("14. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 3: // 终点在第三象限内 + case 6: // 终点在x负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("15. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 4: // 终点在第四象限内 + case 5: // 终点在x正半轴上 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("16. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + default: + break; + } + break; + } + case 5: // 起点在在x正半轴上 + { + maxx = xc + r; + + switch (end) + { + case 1: // 终点在第一象限内 + case 4: // 终点在第四象限内 + if (k > 0) // 大半弧 + { + minx = xc - r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("17. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else // 半弧 + { + printf("18. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 3: // 终点在第三象限内 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("19. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 5: // 终点在x正半轴上 + printf("20. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + break; + + case 6: // 终点在x负半轴上 + minx = xc - r; + if (y[1] > yc) // 逆时针 + { + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (y[1] < yc) // 顺时针 + { + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else + { + printf("21. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + default: + break; + } + break; + } + case 6: // 起点在x负半轴上 + { + minx = xc - r; + + switch (end) + { + case 1: // 终点在第一象限内 + case 7: // 终点在y正半轴上 + if (k > 0) // 大半弧 + { + maxx = xc + r; + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else if (k < 0) // 小半弧 + { + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else // 半弧 + { + printf("22. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 2: // 终点在第二象限内 + case 3: // 终点在第三象限内 + if (k > 0) // 大半弧 + { + maxx = xc + r; + miny = yc - r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("23. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 4: // 终点在第四象限内 + case 8: // 终点在y负半轴上 + if (k > 0) // 大半弧 + { + maxx = xc + r; + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + maxx = MAX(x[0], x[2]); + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("24. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 5: // 终点在x正半轴上 + maxx = xc + r; + if (y[1] > yc) // 顺时针 + { + miny = MIN(y[0], y[2]); + maxy = yc + r; + } + else if (y[1] < yc) // 逆时针 + { + miny = yc - r; + maxy = MAX(y[0], y[2]); + } + else + { + printf("25. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 6: // 终点在x负半轴上 + printf("26. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + break; + + default: + break; + } + break; + } + + case 7: // 起点在y正半轴上 + { + maxy = yc + r; + + switch (end) + { + + case 1: // 终点在第一象限内 + case 2: // 终点在第二象限内 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + miny = yc - r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + } + else // 半弧 + { + printf("27. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 3: // 终点在第三象限内 + case 6: // 终点在x负半轴上 + if (k > 0) // 大半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = yc - r; + } + else if (k < 0) // 小半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = MIN(y[0], y[2]); + } + else // 半弧 + { + printf("28. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 4: // 终点在第四象限内 + case 5: // 终点在x正半轴上 + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + miny = yc - r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + miny = MIN(y[0], y[2]); + } + + else // 半弧 + { + printf("29. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + + case 7: // 终点在y正半轴上 + printf("30. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + break; + + case 8: // 终点在y负半轴上 + miny = yc - r; + if (x[1] > xc) // 顺时针 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + } + else if (x[1] < xc) // 逆时针 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + } + else + { + printf("31. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + default: + break; + } + break; + } + case 8: // 起点在y负半轴上 + { + miny = yc - r; + switch (end) + { + case 1: // 终点在第一象限内 + case 5: // 终点在x正半轴上 + { + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("32. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + } + case 2: // 终点在第二象限内 + case 6: // 终点在x负半轴上 + { + if (k > 0) // 大半弧 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("33. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + } + case 3: // 终点在第三象限内 + case 4: // 终点在第四象限内 + { + if (k > 0) // 大半弧 + { + minx = xc - r; + maxx = xc + r; + maxy = yc + r; + } + else if (k < 0) // 小半弧 + { + minx = MIN(x[0], x[2]); + maxx = MAX(x[0], x[2]); + maxy = MAX(y[0], y[2]); + } + else // 半弧 + { + printf("34. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + } + case 7: // 终点在y正半轴上 + { + maxy = yc + r; + + if (x[1] > xc) // 逆时针 + { + minx = MIN(x[0], x[2]); + maxx = xc + r; + } + else if (x[1] < xc) // 顺时针 + { + minx = xc - r; + maxx = MAX(x[0], x[2]); + } + else + { + printf("35. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + } + break; + } + case 8: // 终点在y负半轴上 + { + printf("36. Impossible in GetMinMax. beg=%d, end=%d\n", beg, end); // 不可能出现的情况 + break; + } + default: + break; + } + break; + } + + default: + break; + } + + if (minx < *pminx) + { + *pminx = minx; + } + + if (miny < *pminy) + { + *pminy = miny; + } + + if (maxx > *pmaxx) + { + *pmaxx = maxx; + } + + if (maxy > *pmaxy) + { + *pmaxy = maxy; + } + + // printf("minx=%.2f, maxx=%.2f, miny=%.2f, maxy=%.2f\n", minx, maxx, miny, maxy); + + return 0; +} + +// 得到直线角度和角度差 +s16 GetAngle(const double bx, const double by, const double ex, const double ey, int * pActAng) +{ + double cosf, angle, length; + s32 dr; + + length = sqrt((ex-bx)*(ex-bx) + (ey-by)*(ey-by)); + if (length != 0) + { + // 计算直线角度(和x正方向的夹角。弧度表示,范围为 0--2PI) + cosf = (ex-bx)/length; + angle = acos(cosf); + if (ey < by) + { + angle = 2*PI - angle; + } + + // 角度差 + if ((angle*RADIAN_ACCURACY - *pActAng) > PI*RADIAN_ACCURACY) // 角度差大于180度, + { + dr = (s32)(angle*RADIAN_ACCURACY - *pActAng - 2*PI* RADIAN_ACCURACY); // 反向到达目标角度 + *pActAng += (int)(2*PI*RADIAN_ACCURACY)+dr; // 实际位置 + } + else if ((angle*RADIAN_ACCURACY - *pActAng) < (-1)*PI*RADIAN_ACCURACY) // 角度差大于180度 + { + dr = (s32)(angle*RADIAN_ACCURACY - *pActAng + 2*PI* RADIAN_ACCURACY); + *pActAng += (int)(-2*PI*RADIAN_ACCURACY)+dr; // 实际位置 + } + else + { + dr = (s32)(angle*RADIAN_ACCURACY - *pActAng); // 正向 + *pActAng += dr; + } + + while (*pActAng > 2*PI*RADIAN_ACCURACY) + { + *pActAng -= 2*PI*RADIAN_ACCURACY; + } + while (*pActAng < 0) + { + *pActAng += 2*PI*RADIAN_ACCURACY; + } + + return dr; + } + return 0; +} + +// 分割圆弧线 +int CalcCurve(double threex[], double threey[], int * pactx, int * pacty, int * pActAng, int stepSize, DataItem * pData, u8 type) +{ + u8 attr; + s16 dx, dy, dr; + + double k, alph, increment; + double xc, yc, r; + double distance2; + double curx, cury, lastx, lasty; + double xrot, yrot; + double len; + int actx, acty; + int ddx, ddy; + int count = 0; + int i; + + // printf("Calc Curve x0=%.2f,y0=%.2f,x1=%.2f,\r\n\t y1=%.2f,x2=%.2f,y2=%.2f\r\n", threex[0],threey[0],threex[1],threey[1],threex[2],threey[2]); + + if(IsThreePointOnALine(threex, threey) == 1) // 3点共线 + { + // 直线和X坐标轴正方向的夹角, 公式: cosφ=∣A1A2+B1B2∣/[√(A1^2+B1^2)√(A2^2+B2^2)] + if (pData != NULL) + { + dr = GetAngle(threex[0], threey[0], threex[2], threey[2], pActAng); + } + return CalcLine(threex[0], threey[0], threex[2], threey[2], pactx, pacty, stepSize, pData, type, dr); // 作为直线分割 + } + + // 计算圆心和半径 + GetArcCenter(threex, threey, &xc, &yc, &r); + + // printf("center=%f,%f,r=%f\r\n", xc, yc, r); + + // 计算弦长和圆心角 + distance2 = ((threex[0]-threex[2])*(threex[0]-threex[2])+(threey[0]-threey[2])*(threey[0]-threey[2])); // 两点间距离就是弦长 + k = ((r*r+r*r)-distance2)/(2*r*r); // cosc = (a*a + b*b - c*c)/2*a*b + if (k < -1) + { + k = -1; + } + else if (k > 1) + { + k = 1; + } + +#if (0) + distance2 = sqrt(distance2); + printf("distance=%f, k=%f\r\n", distance2, k); +#endif + + // 圆心角 + alph = acos(k); +#if (0) + printf("calc alph=%f\r\n", alph); + printf("long double size=%d\r\n", sizeof(long double)); +#endif + // 区分象限和旋转方向 + k = (threex[0]-threex[1])*(threex[2]-threex[1]) + (threey[0]-threey[1])*(threey[2]-threey[1]); // 向量 01 和 向量 21 的夹角的余弦的符号-- > 0 小于90度. < 0 大于90度 = 0, 90 度 + + if (k > 0) // 夹角小于90度, 说明弧是大于半圆 + { + alph = 2*PI-alph; + } + else // 夹角大于等于90度, 说明弧是小于等于半圆, 不需要处理 + { + } +#if (0) + printf("act alph=%f, arclen=%d\r\n", alph, alph*r); +#endif + + // 计算每个针步对应的弧心角大小 + if (fabsl(2*r*r-1.0*stepSize*stepSize)/(2*r*r) > 1) + { + increment = alph; + } + else + { + increment = (acos((2*r*r-1.0*stepSize*stepSize)/(r*r+r*r))); + } + + // 计算分割针步数 + count = (int)(alph/increment+0.5); + if (count == 0) + { + count++; + } + // printf("1.count=%d, increment=%f\r\n", count, increment); + + if (pData == NULL) // 返回个数 + { + return count; + } + + // 重新计算每个针步弧心角 + increment = alph/count; + + // 确定针步增加的角度和方向 + increment *= ArcDir(threex, threey); + // printf("2.count=%d, increment=%f\r\n", count, increment); + + // 起点 + lastx = threex[0]; + lasty = threey[0]; + + actx = *pactx; + acty = *pacty; + + i = 0; + do + { + if (i == count-1) + { + // 最后一个针步 + // printf("the last step\r\n"); + curx = threex[2]; + cury = threey[2]; + } + else + { + // 点 (lastx, lasty) 在圆上旋转 + // printf("before Rotatec point(%f, %f)\r\n", lastx, lasty); + Rotatec(lastx-xc, lasty-yc, &xrot, &yrot, increment); + curx = xrot + xc; + cury = yrot + yc; + } + + ddx = curx-actx; + ddy = cury-acty; + + dx = (s16)(curx-actx+(0.5*(ddx>=0?1:-1))); + dy = (s16)(cury-acty+(0.5*(ddy>=0?1:-1))); + dr = GetAngle(lastx, lasty, curx, cury, pActAng); // 计算直线 (lastx, lasty) 到(curx, cury)和上条直线的角度差 + + attr = 0; + + pData[i].ctrl = type; + pData[i].attr = attr; + pData[i].dx = dx; + pData[i].dy = dy; + pData[i].dr = dr; + + len = sqrt(1.0*dx*dx + 1.0*dy*dy); + pData[i].len = (u16)(len+0.9); + + // printf("after Rotatec point(%f, %f)\r\n", lastx, lasty); + + lastx = curx; + lasty = cury; + actx += dx; + acty += dy; + i++; + + } while(i < count); + + *pactx = actx; + *pacty = acty; + + return count; +} + +//--------------------------------------------------------------------------------------------------------- +// 三次贝塞尔曲线 + +/* cp 在此是四个元素的数组: +cp[0] 为起点,或上图中的 P0 +cp[1] 为第一控制点,或上图中的 P1 +cp[2] 为第二控制点,或上图中的 P2 +cp[3] 为结束点,或上图中的 P3 +t 为参数值,0 <= t <= 1 */ + +typedef struct +{ + double x; + double y; +} Point2D; + +Point2D PointOnCubicBezier(Point2D* cp, double t) +{ + double ax, bx, cx; + double ay, by, cy; + double tSquared, tCubed; + Point2D result; + + /* 计算多项式系数 */ + cx = 3.0 * (cp[1].x - cp[0].x); + bx = 3.0 * (cp[2].x - cp[1].x) - cx; + ax = cp[3].x - cp[0].x - cx - bx; + cy = 3.0 * (cp[1].y - cp[0].y); + by = 3.0 * (cp[2].y - cp[1].y) - cy; + ay = cp[3].y - cp[0].y - cy - by; + + /* 计算t位置的点值 */ + tSquared = t * t; + tCubed = tSquared * t; + result.x =((ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x); + result.y =((ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y); + + return result; +} + +/* 以控制点 cp 所产生的曲线点,填入 Point2D 结构数组。 +调用方必须分配足够的空间以供输出, */ +void ComputeBezier(Point2D* cp, long numberOfPoints, Point2D* curve) +{ + double dt; + long i; + dt = 1.0 / (numberOfPoints - 1); + for(i = 0; i < numberOfPoints; i++) + { + curve[i] = PointOnCubicBezier(cp, i*dt); + } +} + +// 求贝塞尔曲线的最大值和最小值, 1个整数单位精度 +int GetBezierMinMax(const double x[], const double y[], double * pminx, double * pmaxx, double * pminy, double * pmaxy) +{ + long k = 0; + long i = 0; + double sx,sy; + double minx, miny, maxx, maxy; + Point2D cp[4]; + + // 传递参数 + for (i = 0; i < 4; i++) + { + cp[i].x = x[i]; + cp[i].y = y[i]; + } + + // 求控制点总长 + for (i = 0; i < 3; i++) + { + sx = cp[i+1].x - cp[i].x; + sy = cp[i+1].y - cp[i].y; + k += sqrt(sx*sx+sy*sy); // 分割点数 = 总长(精度为0.1mm) + } + + if (k == 0) + { + return -1; + } + + // printf("calc Bezier point num=%ld\n", k); + + Point2D curve[k]; + + ComputeBezier(cp, k, curve); // 分割针步 + + minx = S32_MAX; + maxx = S32_MAX*-1; + miny = S32_MAX; + maxy = S32_MAX*-1; + + // 判断始末点 + if (minx > cp[0].x) { minx = cp[0].x; } + if (maxx < cp[0].x) { maxx = cp[0].x; } + if (miny > cp[0].y) { miny = cp[0].y; } + if (maxy < cp[0].y) { maxy = cp[0].y; } + if (minx > cp[3].x) { minx = cp[3].x; } + if (maxx < cp[3].x) { maxx = cp[3].x; } + if (miny > cp[3].y) { miny = cp[3].y; } + if (maxy < cp[3].y) { maxy = cp[3].y; } + + for (i = 0; i < k; i++) + { + if (minx > cp[i].x) { minx = cp[i].x; } + if (maxx < cp[i].x) { maxx = cp[i].x; } + if (miny > cp[i].y) { miny = cp[i].y; } + if (maxy < cp[i].y) { maxy = cp[i].y; } + } + + //printf("\n BSR minx = %f, maxx = %f, miny = %f, maxy = %f \n",minx,maxx,miny,maxy); + + if (minx < *pminx) + { + *pminx = minx; + } + + if (miny < *pminy) + { + *pminy = miny; + } + + if (maxx > *pmaxx) + { + *pmaxx = maxx; + } + + if (maxy > *pmaxy) + { + *pmaxy = maxy; + } + + return 0; +} + + + +#endif diff --git a/datafile/hpgl/vectorsqrt.h b/datafile/hpgl/vectorsqrt.h new file mode 100644 index 0000000..69c48bd --- /dev/null +++ b/datafile/hpgl/vectorsqrt.h @@ -0,0 +1,135 @@ +#ifndef VECTORSQRT_H +#define VECTORSQRT_H + +#include +#include +#include "config/config.h" +#include "comm/datadef.h" + + +class VSqrtItem : public QObject +{ + Q_OBJECT + + +public: + explicit VSqrtItem(QObject *parent = NULL); + VSqrtItem(const VSqrtItem & item); +public: + VSqrtItem& operator=(const VSqrtItem & item); +private: + void CopyData(const VSqrtItem & item); + +public: + void InitVSItem(); + +public: + int m_sqrttype; // 图形类型, 1, 直线, 2, 圆弧; 3, 三次贝塞尔 + + double m_begx; + double m_begy; // 起点 + double m_midx; + double m_midy; // 中间点1 + double m_midx2; + double m_midy2; // 中间点2 + double m_endx; + double m_endy; // 终点 + +public: + u32 m_code; // 数据类型 + +public: + int m_ownsteplock; // 专有步长和回针标志, != 0, 使用一下的步长和锁针参数. 否则,使用公共的参数 + + u32 m_stepSize; // 步长 + u32 m_blockNum; // 起始锁针针数 + u32 m_blockTimes; // 起始锁针次数 + u32 m_blockjumps; // 起始跳过针数 + u32 m_elockNum; // 结束锁针针数 + u32 m_elockTimes; // 结束锁针次数 + u32 m_elockjumps; // 结束跳过针数 +}; + +class VectorSqrt : public QObject +{ + Q_OBJECT +public: + DataFileHead m_fileHead; // 数据文件头描述 + + explicit VectorSqrt(QObject *parent = NULL); + ~VectorSqrt(); + VectorSqrt(const VectorSqrt & item); + +public: + VectorSqrt& operator=(const VectorSqrt & item); + +private: + void CopyData(const VectorSqrt & item); + +public: + void InitVSqrt(QString name = QString()); + +public: + QString m_filename; // 名称 + int m_anchorSel; // 定位点选择; 0, 和起点重合; 1,图形的左下角; 2, 图形的右下角; 3, 图形的右上角; 4, 图形的左上角; 5, 图形的中心 + +public: + QList m_vSqitItemList; // 图形列表 +public: + // 针步和回针参数 + u32 m_para_stepSize ; // 步长 + u32 m_para_blockNum ; // 起始锁针针数 + u32 m_para_blockTimes ; // 起始锁针次数 + u32 m_para_blockjumps ; // 起始跳过针数 + u32 m_para_elockNum ; // 结束锁针针数 + u32 m_para_elockTimes ; // 结束锁针次数 + u32 m_para_elockjumps ; // 结束跳过针数 + +public: + //这个过程应该放在不同的文件实现中而不是放在 VectorSqrt 这里生成数据中应该分离开 + int CreateDs16FromSqrt(QByteArray & ds16Ary); + int CreateDs8FromDs16(const QByteArray & ds16Ary, QByteArray & ds8Ary); + + int CreateDs4FromSqrt(QByteArray & ds4Ary); + int CreateDs2FromDs4(const QByteArray & ds4Ary, QByteArray & ds2Ary); + +public: + void SetAnchor(int nX,int nY); + void SetBegin(int nX,int nY); + +private: + int m_anchorX;//定位点X + int m_anchorY;//定位点Y + int m_beginX;//数据起点坐标X + int m_beginY;//数据起点坐标Y + + + +signals: + +public slots: +}; + +int GetDataMinMax(DataItem * pData, int nums, s32 & minx, s32 & miny, s32 & maxx, s32 & maxy); + + +// 图形算法 +// 直线 +int CalcLine(double x0, double y0, double x1, double y1, int * pactx, int * pacty, int stepSize, DataItem * pData, u8 type, s16 dr); + +// 三点圆弧 +int CalcCurve(double threex[], double threey[], int * pactx, int * pacty, int * pActAng, int stepSize, DataItem * pData, u8 type); + +void Rotatec(double xin, double yin, double * px, double * py, double angle); +int ArcDir(const double x[], const double y[]); +int IsThreePointOnALine(const double threex[], const double threey[]); +int GetArcCenter(const double x[], const double y[], double * pxc, double * pyc, double * pr); +int GetArcRectAndAngle(const double x[], const double y[], double * minx, double * maxx, double * miny, double * maxy, double * startangle, double * endangle); +int GetArcMinMax(const double x[], const double y[], double * pminx, double * pmaxx, double * pminy, double * pmaxy); +s16 GetAngle(const double bx, const double by, const double ex, const double ey, int * pActAng); + +// 三次贝塞尔 +int GetBezierMinMax(const double x[], const double y[], double * pminx, double * pmaxx, double * pminy, double * pmaxy); + + +#endif // VECTORSQRT_H diff --git a/datafile/qrencode/bitstream.c b/datafile/qrencode/bitstream.c new file mode 100644 index 0000000..f620050 --- /dev/null +++ b/datafile/qrencode/bitstream.c @@ -0,0 +1,231 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include + +#include "bitstream.h" + +#define DEFAULT_BUFSIZE (128) + +BitStream *BitStream_new(void) +{ + BitStream *bstream; + + bstream = (BitStream *)malloc(sizeof(BitStream)); + if(bstream == NULL) return NULL; + + bstream->length = 0; + bstream->data = (unsigned char *)malloc(DEFAULT_BUFSIZE); + if(bstream->data == NULL) { + free(bstream); + return NULL; + } + bstream->datasize = DEFAULT_BUFSIZE; + + return bstream; +} + +#ifdef WITH_TESTS +BitStream *BitStream_newWithBits(size_t size, unsigned char *bits) +{ + BitStream *bstream; + + if(size == 0) return BitStream_new(); + + bstream = (BitStream *)malloc(sizeof(BitStream)); + if(bstream == NULL) return NULL; + + bstream->data = (unsigned char *)malloc(size); + if(bstream->data == NULL) { + free(bstream); + return NULL; + } + + bstream->length = size; + bstream->datasize = size; + memcpy(bstream->data, bits, size); + + return bstream; +} +#endif + +static int BitStream_expand(BitStream *bstream) +{ + unsigned char *data; + + data = (unsigned char *)realloc(bstream->data, bstream->datasize * 2); + if(data == NULL) { + return -1; + } + + bstream->data = data; + bstream->datasize *= 2; + + return 0; +} + +static void BitStream_writeNum(unsigned char *dest, size_t bits, unsigned int num) +{ + unsigned int mask; + size_t i; + unsigned char *p; + + p = dest; + mask = 1U << (bits - 1); + for(i = 0; i < bits; i++) { + if(num & mask) { + *p = 1; + } else { + *p = 0; + } + p++; + mask = mask >> 1; + } +} + +static void BitStream_writeBytes(unsigned char *dest, size_t size, unsigned char *data) +{ + unsigned char mask; + size_t i, j; + unsigned char *p; + + p = dest; + for(i = 0; i < size; i++) { + mask = 0x80; + for(j = 0; j < 8; j++) { + if(data[i] & mask) { + *p = 1; + } else { + *p = 0; + } + p++; + mask = mask >> 1; + } + } +} + +int BitStream_append(BitStream *bstream, BitStream *arg) +{ + int ret; + + if(arg == NULL) { + return -1; + } + if(arg->length == 0) { + return 0; + } + + while(bstream->length + arg->length > bstream->datasize) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + + memcpy(bstream->data + bstream->length, arg->data, arg->length); + bstream->length += arg->length; + + return 0; +} + +int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num) +{ + int ret; + + if(bits == 0) return 0; + + while(bstream->datasize - bstream->length < bits) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + BitStream_writeNum(bstream->data + bstream->length, bits, num); + bstream->length += bits; + + return 0; +} + +int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data) +{ + int ret; + + if(size == 0) return 0; + + while(bstream->datasize - bstream->length < size * 8) { + ret = BitStream_expand(bstream); + if(ret < 0) return ret; + } + BitStream_writeBytes(bstream->data + bstream->length, size, data); + bstream->length += size * 8; + + return 0; +} + +unsigned char *BitStream_toByte(BitStream *bstream) +{ + size_t i, j, size, bytes, oddbits; + unsigned char *data, v; + unsigned char *p; + + size = BitStream_size(bstream); + if(size == 0) { + return NULL; + } + data = (unsigned char *)malloc((size + 7) / 8); + if(data == NULL) { + return NULL; + } + + bytes = size / 8; + + p = bstream->data; + for(i = 0; i < bytes; i++) { + v = 0; + for(j = 0; j < 8; j++) { + v = (unsigned char)(v << 1); + v |= *p; + p++; + } + data[i] = v; + } + oddbits = size & 7; + if(oddbits > 0) { + v = 0; + for(j = 0; j < oddbits; j++) { + v = (unsigned char)(v << 1); + v |= *p; + p++; + } + data[bytes] = (unsigned char)(v << (8 - oddbits)); + } + + return data; +} + +void BitStream_free(BitStream *bstream) +{ + if(bstream != NULL) { + free(bstream->data); + free(bstream); + } +} diff --git a/datafile/qrencode/bitstream.h b/datafile/qrencode/bitstream.h new file mode 100644 index 0000000..70f3e1d --- /dev/null +++ b/datafile/qrencode/bitstream.h @@ -0,0 +1,43 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +typedef struct { + size_t length; + size_t datasize; + unsigned char *data; +} BitStream; + +extern BitStream *BitStream_new(void); +#ifdef WITH_TESTS +extern BitStream *BitStream_newWithBits(size_t size, unsigned char *bits); +#endif +extern int BitStream_append(BitStream *bstream, BitStream *arg); +extern int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num); +extern int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data); +#define BitStream_size(__bstream__) (__bstream__->length) +#define BitStream_reset(__bstream__) (__bstream__->length = 0) +extern unsigned char *BitStream_toByte(BitStream *bstream); +extern void BitStream_free(BitStream *bstream); + +#endif /* BITSTREAM_H */ diff --git a/datafile/qrencode/config.h b/datafile/qrencode/config.h new file mode 100644 index 0000000..597c420 --- /dev/null +++ b/datafile/qrencode/config.h @@ -0,0 +1,102 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the iconv() function and it works. */ +#undef HAVE_ICONV + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if using pthread is enabled. */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if using libpng is enabled. */ +#undef HAVE_PNG + +/* Define to 1 if using SDL is enabled. */ +#undef HAVE_SDL + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Major version number */ +#undef MAJOR_VERSION +#define MAJOR_VERSION 1 +/* Micro version number */ +#undef MICRO_VERSION +#define MICRO_VERSION 1 +/* Minor version number */ +#undef MINOR_VERSION +#define MINOR_VERSION 1 +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION +#define VERSION (char*)1 +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to 'static' if no test programs will be compiled. */ +#define STATIC_IN_RELEASE static +#undef WITH_TESTS + diff --git a/datafile/qrencode/mask.c b/datafile/qrencode/mask.c new file mode 100644 index 0000000..4bf2371 --- /dev/null +++ b/datafile/qrencode/mask.c @@ -0,0 +1,357 @@ +/* + * qrencode - QR Code encoder + * + * Masking. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mask.h" + +STATIC_IN_RELEASE int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + int blacks = 0; + + format = QRspec_getFormatInfo(mask, level); + + for(i = 0; i < 8; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * 8 + width - 1 - i] = v; + if(i < 6) { + frame[width * i + 8] = v; + } else { + frame[width * (i + 1) + 8] = v; + } + format= format >> 1; + } + for(i = 0; i < 7; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * (width - 7 + i) + 8] = v; + if(i == 0) { + frame[width * 8 + 7] = v; + } else { + frame[width * 8 + 6 - i] = v; + } + format= format >> 1; + } + + return blacks; +} + +/** + * Demerit coefficients. + * See Section 8.8.2, pp.45, JIS X0510:2004. + */ +#define N1 (3) +#define N2 (3) +#define N3 (40) +#define N4 (10) + +#define MASKMAKER(__exp__) \ + int x, y;\ + int b = 0;\ +\ + for(y = 0; y < width; y++) {\ + for(x = 0; x < width; x++) {\ + if(*s & 0x80) {\ + *d = *s;\ + } else {\ + *d = *s ^ ((__exp__) == 0);\ + }\ + b += (int)(*d & 1);\ + s++; d++;\ + }\ + }\ + return b; + +static int Mask_mask0(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((x+y)&1) +} + +static int Mask_mask1(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(y&1) +} + +static int Mask_mask2(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(x%3) +} + +static int Mask_mask3(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((x+y)%3) +} + +static int Mask_mask4(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((y/2)+(x/3))&1) +} + +static int Mask_mask5(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((x*y)&1)+(x*y)%3) +} + +static int Mask_mask6(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)&1)+(x*y)%3)&1) +} + +static int Mask_mask7(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)%3)+((x+y)&1))&1) +} + +#define maskNum (8) +typedef int MaskMaker(int, const unsigned char *, unsigned char *); +static MaskMaker *maskMakers[maskNum] = { + Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3, + Mask_mask4, Mask_mask5, Mask_mask6, Mask_mask7 +}; + +#ifdef WITH_TESTS +unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask) +{ + unsigned char *masked; + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + + return masked; +} +#endif + +unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned char *masked; + + if(mask < 0 || mask >= maskNum) { + errno = EINVAL; + return NULL; + } + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + Mask_writeFormatInformation(width, masked, mask, level); + + return masked; +} + + +//static int n1; +//static int n2; +//static int n3; +//static int n4; + +STATIC_IN_RELEASE int Mask_calcN1N3(int length, int *runLength) +{ + int i; + int demerit = 0; + int fact; + + for(i = 0; i < length; i++) { + if(runLength[i] >= 5) { + demerit += N1 + (runLength[i] - 5); + //n1 += N1 + (runLength[i] - 5); + } + if((i & 1)) { + if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) { + fact = runLength[i] / 3; + if(runLength[i-2] == fact && + runLength[i-1] == fact && + runLength[i+1] == fact && + runLength[i+2] == fact) { + if(i == 3 || runLength[i-3] >= 4 * fact) { + demerit += N3; + //n3 += N3; + } else if(i+4 >= length || runLength[i+3] >= 4 * fact) { + demerit += N3; + //n3 += N3; + } + } + } + } + } + + return demerit; +} + +STATIC_IN_RELEASE int Mask_calcN2(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + unsigned char b22, w22; + int demerit = 0; + + p = frame + width + 1; + for(y = 1; y < width; y++) { + for(x = 1; x < width; x++) { + b22 = p[0] & p[-1] & p[-width] & p [-width-1]; + w22 = p[0] | p[-1] | p[-width] | p [-width-1]; + if((b22 | (w22 ^ 1))&1) { + demerit += N2; + } + p++; + } + p++; + } + + return demerit; +} + +STATIC_IN_RELEASE int Mask_calcRunLengthH(int width, unsigned char *frame, int *runLength) +{ + int head; + int i; + unsigned char prev; + + if(frame[0] & 1) { + runLength[0] = -1; + head = 1; + } else { + head = 0; + } + runLength[head] = 1; + prev = frame[0]; + + for(i = 1; i < width; i++) { + if((frame[i] ^ prev) & 1) { + head++; + runLength[head] = 1; + prev = frame[i]; + } else { + runLength[head]++; + } + } + + return head + 1; +} + +STATIC_IN_RELEASE int Mask_calcRunLengthV(int width, unsigned char *frame, int *runLength) +{ + int head; + int i; + unsigned char prev; + + if(frame[0] & 1) { + runLength[0] = -1; + head = 1; + } else { + head = 0; + } + runLength[head] = 1; + prev = frame[0]; + + for(i = 1; i < width; i++) { + if((frame[i * width] ^ prev) & 1) { + head++; + runLength[head] = 1; + prev = frame[i * width]; + } else { + runLength[head]++; + } + } + + return head + 1; +} + +STATIC_IN_RELEASE int Mask_evaluateSymbol(int width, unsigned char *frame) +{ + int x, y; + int demerit = 0; + int runLength[QRSPEC_WIDTH_MAX + 1]; + int length; + + demerit += Mask_calcN2(width, frame); + + for(y = 0; y < width; y++) { + length = Mask_calcRunLengthH(width, frame + y * width, runLength); + demerit += Mask_calcN1N3(length, runLength); + } + + for(x = 0; x < width; x++) { + length = Mask_calcRunLengthV(width, frame + x, runLength); + demerit += Mask_calcN1N3(length, runLength); + } + + return demerit; +} + +unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level) +{ + int i; + unsigned char *mask, *bestMask; + int minDemerit = INT_MAX; + int blacks; + int bratio; + int demerit; + int w2 = width * width; + + mask = (unsigned char *)malloc((size_t)w2); + if(mask == NULL) return NULL; + bestMask = (unsigned char *)malloc((size_t)w2); + if(bestMask == NULL) { + free(mask); + return NULL; + } + + for(i = 0; i < maskNum; i++) { +// n1 = n2 = n3 = n4 = 0; + demerit = 0; + blacks = maskMakers[i](width, frame, mask); + blacks += Mask_writeFormatInformation(width, mask, i, level); + bratio = (200 * blacks + w2) / w2 / 2; /* (int)(100*blacks/w2+0.5) */ + demerit = (abs(bratio - 50) / 5) * N4; +// n4 = demerit; + demerit += Mask_evaluateSymbol(width, mask); +// printf("(%d,%d,%d,%d)=%d\n", n1, n2, n3 ,n4, demerit); + if(demerit < minDemerit) { + minDemerit = demerit; + memcpy(bestMask, mask, (size_t)w2); + } + } + free(mask); + return bestMask; +} diff --git a/datafile/qrencode/mask.h b/datafile/qrencode/mask.h new file mode 100644 index 0000000..169e64b --- /dev/null +++ b/datafile/qrencode/mask.h @@ -0,0 +1,38 @@ +/* + * qrencode - QR Code encoder + * + * Masking. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MASK_H +#define MASK_H + +extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int Mask_calcN2(int width, unsigned char *frame); +extern int Mask_calcN1N3(int length, int *runLength); +extern int Mask_calcRunLengthH(int width, unsigned char *frame, int *runLength); +extern int Mask_calcRunLengthV(int width, unsigned char *frame, int *runLength); +extern int Mask_evaluateSymbol(int width, unsigned char *frame); +extern int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* MASK_H */ diff --git a/datafile/qrencode/mmask.c b/datafile/qrencode/mmask.c new file mode 100644 index 0000000..5f09a1e --- /dev/null +++ b/datafile/qrencode/mmask.c @@ -0,0 +1,177 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "qrencode.h" +#include "mqrspec.h" +#include "mmask.h" + +STATIC_IN_RELEASE void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + + format = MQRspec_getFormatInfo(mask, version, level); + + for(i = 0; i < 8; i++) { + v = 0x84 | (format & 1); + frame[width * (i + 1) + 8] = v; + format = format >> 1; + } + for(i = 0; i < 7; i++) { + v = 0x84 | (format & 1); + frame[width * 8 + 7 - i] = v; + format = format >> 1; + } +} + +#define MASKMAKER(__exp__) \ + int x, y;\ +\ + for(y = 0; y < width; y++) {\ + for(x = 0; x < width; x++) {\ + if(*s & 0x80) {\ + *d = *s;\ + } else {\ + *d = *s ^ ((__exp__) == 0);\ + }\ + s++; d++;\ + }\ + } + +static void Mask_mask0(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(y&1) +} + +static void Mask_mask1(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER(((y/2)+(x/3))&1) +} + +static void Mask_mask2(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x*y)&1)+(x*y)%3)&1) +} + +static void Mask_mask3(int width, const unsigned char *s, unsigned char *d) +{ + MASKMAKER((((x+y)&1)+((x*y)%3))&1) +} + +#define maskNum (4) +typedef void MaskMaker(int, const unsigned char *, unsigned char *); +static MaskMaker *maskMakers[maskNum] = { + Mask_mask0, Mask_mask1, Mask_mask2, Mask_mask3 +}; + +#ifdef WITH_TESTS +unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask) +{ + unsigned char *masked; + + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + + return masked; +} +#endif + +unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned char *masked; + int width; + + if(mask < 0 || mask >= maskNum) { + errno = EINVAL; + return NULL; + } + + width = MQRspec_getWidth(version); + masked = (unsigned char *)malloc((size_t)(width * width)); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + MMask_writeFormatInformation(version, width, masked, mask, level); + + return masked; +} + +STATIC_IN_RELEASE int MMask_evaluateSymbol(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + int sum1 = 0, sum2 = 0; + + p = frame + width * (width - 1); + for(x = 1; x < width; x++) { + sum1 += (p[x] & 1); + } + + p = frame + width * 2 - 1; + for(y = 1; y < width; y++) { + sum2 += (*p & 1); + p += width; + } + + return (sum1 <= sum2)?(sum1 * 16 + sum2):(sum2 * 16 + sum1); +} + +unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level) +{ + int i; + unsigned char *mask, *bestMask; + int maxScore = 0; + int score; + int width; + + width = MQRspec_getWidth(version); + + mask = (unsigned char *)malloc((size_t)(width * width)); + if(mask == NULL) return NULL; + bestMask = NULL; + + for(i = 0; i < maskNum; i++) { + score = 0; + maskMakers[i](width, frame, mask); + MMask_writeFormatInformation(version, width, mask, i, level); + score = MMask_evaluateSymbol(width, mask); + if(score > maxScore) { + maxScore = score; + free(bestMask); + bestMask = mask; + mask = (unsigned char *)malloc((size_t)(width * width)); + if(mask == NULL) break; + } + } + free(mask); + return bestMask; +} diff --git a/datafile/qrencode/mmask.h b/datafile/qrencode/mmask.h new file mode 100644 index 0000000..56a58cd --- /dev/null +++ b/datafile/qrencode/mmask.h @@ -0,0 +1,34 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MMASK_H +#define MMASK_H + +extern unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int MMask_evaluateSymbol(int width, unsigned char *frame); +extern void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* MMASK_H */ diff --git a/datafile/qrencode/mqrspec.c b/datafile/qrencode/mqrspec.c new file mode 100644 index 0000000..87205fe --- /dev/null +++ b/datafile/qrencode/mqrspec.c @@ -0,0 +1,232 @@ +/* + * qrencode - QR Code encoder + * + * Micro QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "mqrspec.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; ///< Edge length of the symbol + int ec[4]; ///< Number of ECC code (bytes) +} MQRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004. + */ +static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = { + { 0, {0, 0, 0, 0}}, + { 11, {2, 0, 0, 0}}, + { 13, {5, 6, 0, 0}}, + { 15, {6, 8, 0, 0}}, + { 17, {8, 10, 14, 0}} +}; + +int MQRspec_getDataLengthBit(int version, QRecLevel level) +{ + int w; + int ecc; + + w = mqrspecCapacity[version].width - 1; + ecc = mqrspecCapacity[version].ec[level]; + if(ecc == 0) return 0; + return w * w - 64 - ecc * 8; +} + +int MQRspec_getDataLength(int version, QRecLevel level) +{ + return (MQRspec_getDataLengthBit(version, level) + 4) / 8; +} + +int MQRspec_getECCLength(int version, QRecLevel level) +{ + return mqrspecCapacity[version].ec[level]; +} + +int MQRspec_getWidth(int version) +{ + return mqrspecCapacity[version].width; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * See Table 3 (pp.107) of Appendix 1, JIS X0510:2004. + */ +static const int lengthTableBits[4][4] = { + { 3, 4, 5, 6}, + { 0, 3, 4, 5}, + { 0, 0, 4, 5}, + { 0, 0, 3, 4} +}; + +int MQRspec_lengthIndicator(QRencodeMode mode, int version) +{ + return lengthTableBits[mode][version - 1]; +} + +int MQRspec_maximumWords(QRencodeMode mode, int version) +{ + int bits; + int words; + + bits = lengthTableBits[mode][version - 1]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_mqrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3}, + {0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4}, + {0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d}, + {0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba} +}; + +/* See Table 10 of Appendix 1. (pp.115) */ +static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = { + {-1, -1, -1}, + { 0, -1, -1}, + { 1, 2, -1}, + { 3, 4, -1}, + { 5, 6, 7} +}; + +unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level) +{ + int type; + + if(mask < 0 || mask > 3) return 0; + if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0; + if(level == QR_ECLEVEL_H) return 0; + type = typeTable[version][level]; + if(type < 0) return 0; + + return formatInfo[mask][type]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Put a finder pattern. + * @param frame + * @param width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y = 0; y < 7; y++) { + for(x = 0; x < 7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + +static unsigned char *MQRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + + width = mqrspecCapacity[version].width; + frame = (unsigned char *)malloc((size_t)(width * width)); + if(frame == NULL) return NULL; + + memset(frame, 0, (size_t)(width * width)); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + /* Separator */ + p = frame; + for(y = 0; y < 7; y++) { + p[7] = 0xc0; + p += width; + } + memset(frame + width * 7, 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8 + 1, 0x84, 8); + p = frame + width + 8; + for(y = 0; y < 7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + 8; + q = frame + width * 8; + for(x = 1; x < width-7; x++) { + *p = 0x90 | (x & 1); + *q = 0x90 | (x & 1); + p++; + q += width; + } + + return frame; +} + +unsigned char *MQRspec_newFrame(int version) +{ + if(version < 1 || version > MQRSPEC_VERSION_MAX) return NULL; + + return MQRspec_createFrame(version); +} diff --git a/datafile/qrencode/mqrspec.h b/datafile/qrencode/mqrspec.h new file mode 100644 index 0000000..0eaa490 --- /dev/null +++ b/datafile/qrencode/mqrspec.h @@ -0,0 +1,150 @@ +/* + * qrencode - QR Code encoder + * + * Micro QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MQRSPEC_H +#define MQRSPEC_H + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define MQRSPEC_WIDTH_MAX 17 + +/** + * Return maximum data code length (bits) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bits) + */ +extern int MQRspec_getDataLengthBit(int version, QRecLevel level); + +/** + * Return maximum data code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bytes) + */ +extern int MQRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return ECC size (bytes) + */ +extern int MQRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level error correction level + * @return version number + */ +extern int MQRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version version of the symbol + * @return width + */ +extern int MQRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version version of the symbol + * @return number of remainder bits + */ +extern int MQRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of length indicator for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the size of the appropriate length indicator (bits). + */ +extern int MQRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the maximum length (bytes) + */ +extern int MQRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version vesion of the symbol + * @return BCH encoded version information pattern + */ +extern unsigned int MQRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask mask number + * @param version version of the symbol + * @param level error correction level + * @return BCH encoded format information pattern + */ +extern unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * @param version version of the symbol + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *MQRspec_newFrame(int version); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 in Appendix 1 of JIS X0510:2004, pp.107. + */ +#define MQRSPEC_MODEID_NUM 0 +#define MQRSPEC_MODEID_AN 1 +#define MQRSPEC_MODEID_8 2 +#define MQRSPEC_MODEID_KANJI 3 + +#endif /* MQRSPEC_H */ diff --git a/datafile/qrencode/qrenc.c b/datafile/qrencode/qrenc.c new file mode 100644 index 0000000..c09c4ab --- /dev/null +++ b/datafile/qrencode/qrenc.c @@ -0,0 +1,1453 @@ +/** + * qrencode - QR Code encoder + * + * QR Code encoding tool + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include +#include +#if HAVE_PNG +#include +#endif + +#include "qrencode.h" + +#define INCHES_PER_METER (100.0/2.54) + +static int casesensitive = 1; +static int eightbit = 0; +static int version = 0; +static int size = 3; +static int margin = -1; +static int dpi = 72; +static int structured = 0; +static int rle = 0; +static int svg_path = 0; +static int micro = 0; +static int inline_svg = 0; +static int strict_versioning = 0; +static QRecLevel level = QR_ECLEVEL_L; +static QRencodeMode hint = QR_MODE_8; +static unsigned char fg_color[4] = {0, 0, 0, 255}; +static unsigned char bg_color[4] = {255, 255, 255, 255}; + +static int verbose = 0; + +enum imageType { + PNG_TYPE, + PNG32_TYPE, + EPS_TYPE, + SVG_TYPE, + XPM_TYPE, + ANSI_TYPE, + ANSI256_TYPE, + ASCII_TYPE, + ASCIIi_TYPE, + UTF8_TYPE, + ANSIUTF8_TYPE, + ANSI256UTF8_TYPE, + UTF8i_TYPE, + ANSIUTF8i_TYPE +}; + +static enum imageType image_type = PNG_TYPE; + +static const struct option options[] = { + {"help" , no_argument , NULL, 'h'}, + {"output" , required_argument, NULL, 'o'}, + {"read-from" , required_argument, NULL, 'r'}, + {"level" , required_argument, NULL, 'l'}, + {"size" , required_argument, NULL, 's'}, + {"symversion" , required_argument, NULL, 'v'}, + {"margin" , required_argument, NULL, 'm'}, + {"dpi" , required_argument, NULL, 'd'}, + {"type" , required_argument, NULL, 't'}, + {"structured" , no_argument , NULL, 'S'}, + {"kanji" , no_argument , NULL, 'k'}, + {"casesensitive" , no_argument , NULL, 'c'}, + {"ignorecase" , no_argument , NULL, 'i'}, + {"8bit" , no_argument , NULL, '8'}, + {"micro" , no_argument , NULL, 'M'}, + {"rle" , no_argument , &rle, 1}, + {"svg-path" , no_argument , &svg_path, 1}, + {"inline" , no_argument , &inline_svg, 1}, + {"strict-version", no_argument , &strict_versioning, 1}, + {"foreground" , required_argument, NULL, 'f'}, + {"background" , required_argument, NULL, 'b'}, + {"version" , no_argument , NULL, 'V'}, + {"verbose" , no_argument , &verbose, 1}, + {NULL, 0, NULL, 0} +}; + +static char *optstring = "ho:r:l:s:v:m:d:t:Skci8MV"; + +static void usage(int help, int longopt, int status) +{ + FILE *out = status ? stderr : stdout; + fprintf(out, +"qrencode version %s\n" +"Copyright (C) 2006-2017 Kentaro Fukuchi\n", QRcode_APIVersionString()); + if(help) { + if(longopt) { + fprintf(out, +"Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n" +"Encode input data in a QR Code and save as a PNG or EPS image.\n\n" +" -h, --help display the help message. -h displays only the help of short\n" +" options.\n\n" +" -o FILENAME, --output=FILENAME\n" +" write image to FILENAME. If '-' is specified, the result\n" +" will be output to standard output. If -S is given, structured\n" +" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n" +" (suffix is removed from FILENAME, if specified)\n\n" +" -r FILENAME, --read-from=FILENAME\n" +" read input data from FILENAME.\n\n" +" -s NUMBER, --size=NUMBER\n" +" specify module size in dots (pixels). (default=3)\n\n" +" -l {LMQH}, --level={LMQH}\n" +" specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n\n" +" -v NUMBER, --symversion=NUMBER\n" +" specify the minimum version of the symbol. See SYMBOL VERSIONS\n" +" for more information. (default=auto)\n\n" +" -m NUMBER, --margin=NUMBER\n" +" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n" +" -d NUMBER, --dpi=NUMBER\n" +" specify the DPI of the generated PNG. (default=72)\n\n" +" -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8},\n" +" --type={PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8}\n" +" specify the type of the generated image. (default=PNG)\n\n" +" -S, --structured\n" +" make structured symbols. Version must be specified with '-v'.\n\n" +" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n" +" -c, --casesensitive\n" +" encode lower-case alphabet characters in 8-bit mode. (default)\n\n" +" -i, --ignorecase\n" +" ignore case distinctions and use only upper-case characters.\n\n" +" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n" +" -M, --micro encode in a Micro QR Code.\n\n" +" --rle enable run-length encoding for SVG.\n\n" +" --svg-path\n" +" use single path to draw modules for SVG.\n\n" +" --inline only useful for SVG output, generates an SVG without the XML tag.\n\n" +" --foreground=RRGGBB[AA]\n" +" --background=RRGGBB[AA]\n" +" specify foreground/background color in hexadecimal notation.\n" +" 6-digit (RGB) or 8-digit (RGBA) form are supported.\n" +" Color output support available only in PNG, EPS and SVG.\n\n" +" --strict-version\n" +" disable automatic version number adjustment. If the input data is\n" +" too large for the specified version, the program exits with the\n" +" code of 1.\n\n" +" -V, --version\n" +" display the version number and copyrights of the qrencode.\n\n" +" --verbose\n" +" display verbose information to stderr.\n\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +"SYMBOL VERSIONS\n" +" The symbol versions of QR Code range from Version 1 to Version\n" +" 40. Each version has a different module configuration or number\n" +" of modules, ranging from Version 1 (21 x 21 modules) up to\n" +" Version 40 (177 x 177 modules). Each higher version number\n" +" comprises 4 additional modules per side by default. See\n" +" http://www.qrcode.com/en/about/version.html for a detailed\n" +" version list.\n" + + ); + } else { + fprintf(out, +"Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n" +"Encode input data in a QR Code and save as a PNG or EPS image.\n\n" +" -h display this message.\n" +" --help display the usage of long options.\n" +" -o FILENAME write image to FILENAME. If '-' is specified, the result\n" +" will be output to standard output. If -S is given, structured\n" +" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n" +" (suffix is removed from FILENAME, if specified)\n" +" -r FILENAME read input data from FILENAME.\n" +" -s NUMBER specify module size in dots (pixels). (default=3)\n" +" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n" +" (default=L)\n" +" -v NUMBER specify the minimum version of the symbol. (default=auto)\n" +" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n" +" -d NUMBER specify the DPI of the generated PNG. (default=72)\n" +" -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,UTF8i,ANSIUTF8,ANSIUTF8i,ANSI256UTF8}\n" +" specify the type of the generated image. (default=PNG)\n" +" -S make structured symbols. Version number must be specified with '-v'.\n" +" -k assume that the input text contains kanji (shift-jis).\n" +" -c encode lower-case alphabet characters in 8-bit mode. (default)\n" +" -i ignore case distinctions and use only upper-case characters.\n" +" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n" +" -M encode in a Micro QR Code.\n" +" -V display the version number and copyrights of the qrencode.\n" +" [STRING] input data. If it is not specified, data will be taken from\n" +" standard input.\n\n" +" Try \"qrencode --help\" for more options.\n" + ); + } + } +} + +static int color_set(unsigned char color[4], const char *value) +{ + int len = strlen(value); + int i, count; + unsigned int col[4]; + if(len == 6) { + count = sscanf(value, "%02x%02x%02x%n", &col[0], &col[1], &col[2], &len); + if(count < 3 || len != 6) { + return -1; + } + for(i = 0; i < 3; i++) { + color[i] = col[i]; + } + color[3] = 255; + } else if(len == 8) { + count = sscanf(value, "%02x%02x%02x%02x%n", &col[0], &col[1], &col[2], &col[3], &len); + if(count < 4 || len != 8) { + return -1; + } + for(i = 0; i < 4; i++) { + color[i] = col[i]; + } + } else { + return -1; + } + return 0; +} + +#define MAX_DATA_SIZE (7090 * 2) /* timed by the safty factor 2 */ +static unsigned char data_buffer[MAX_DATA_SIZE]; +static unsigned char *readFile(FILE *fp, int *length) +{ + int ret; + + ret = fread(data_buffer, 1, MAX_DATA_SIZE, fp); + if(ret == 0) { + fprintf(stderr, "No input data.\n"); + exit(EXIT_FAILURE); + } + if(feof(fp) == 0) { + fprintf(stderr, "Input data is too large.\n"); + exit(EXIT_FAILURE); + } + + data_buffer[ret] = '\0'; + *length = ret; + + return data_buffer; +} + +static FILE *openFile(const char *outfile) +{ + FILE *fp; + + if(outfile == NULL || (outfile[0] == '-' && outfile[1] == '\0')) { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + return fp; +} + +#if HAVE_PNG +static void fillRow(unsigned char *row, int num, const unsigned char color[]) +{ + int i; + + for(i = 0; i < num; i++) { + memcpy(row, color, 4); + row += 4; + } +} +#endif + +static int writePNG(const QRcode *qrcode, const char *outfile, enum imageType type) +{ +#if HAVE_PNG + static FILE *fp; // avoid clobbering by setjmp. + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette = NULL; + png_byte alpha_values[2]; + unsigned char *row, *p, *q; + int x, y, xx, yy, bit; + int realwidth; + + realwidth = (qrcode->width + margin * 2) * size; + if(type == PNG_TYPE) { + row = (unsigned char *)malloc((size_t)((realwidth + 7) / 8)); + } else if(type == PNG32_TYPE) { + row = (unsigned char *)malloc((size_t)realwidth * 4); + } else { + fprintf(stderr, "Internal error.\n"); + exit(EXIT_FAILURE); + } + if(row == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + if(outfile[0] == '-' && outfile[1] == '\0') { + fp = stdout; + } else { + fp = fopen(outfile, "wb"); + if(fp == NULL) { + fprintf(stderr, "Failed to create file: %s\n", outfile); + perror(NULL); + exit(EXIT_FAILURE); + } + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(png_ptr == NULL) { + fprintf(stderr, "Failed to initialize PNG writer.\n"); + exit(EXIT_FAILURE); + } + + info_ptr = png_create_info_struct(png_ptr); + if(info_ptr == NULL) { + fprintf(stderr, "Failed to initialize PNG write.\n"); + exit(EXIT_FAILURE); + } + + if(setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fprintf(stderr, "Failed to write PNG image.\n"); + exit(EXIT_FAILURE); + } + + if(type == PNG_TYPE) { + palette = (png_colorp) malloc(sizeof(png_color) * 2); + if(palette == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + palette[0].red = fg_color[0]; + palette[0].green = fg_color[1]; + palette[0].blue = fg_color[2]; + palette[1].red = bg_color[0]; + palette[1].green = bg_color[1]; + palette[1].blue = bg_color[2]; + alpha_values[0] = fg_color[3]; + alpha_values[1] = bg_color[3]; + png_set_PLTE(png_ptr, info_ptr, palette, 2); + png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL); + } + + png_init_io(png_ptr, fp); + if(type == PNG_TYPE) { + png_set_IHDR(png_ptr, info_ptr, + (unsigned int)realwidth, (unsigned int)realwidth, + 1, + PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + } else { + png_set_IHDR(png_ptr, info_ptr, + (unsigned int)realwidth, (unsigned int)realwidth, + 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + } + png_set_pHYs(png_ptr, info_ptr, + dpi * INCHES_PER_METER, + dpi * INCHES_PER_METER, + PNG_RESOLUTION_METER); + png_write_info(png_ptr, info_ptr); + + if(type == PNG_TYPE) { + /* top margin */ + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + q = row; + q += margin * size / 8; + bit = 7 - (margin * size % 8); + for(x = 0; x < qrcode->width; x++) { + for(xx = 0; xx < size; xx++) { + *q ^= (*p & 1) << bit; + bit--; + if(bit < 0) { + q++; + bit = 7; + } + } + p++; + } + for(yy = 0; yy < size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + memset(row, 0xff, (size_t)((realwidth + 7) / 8)); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + } else { + /* top margin */ + fillRow(row, realwidth, bg_color); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + fillRow(row, realwidth, bg_color); + for(x = 0; x < qrcode->width; x++) { + for(xx = 0; xx < size; xx++) { + if(*p & 1) { + memcpy(&row[((margin + x) * size + xx) * 4], fg_color, 4); + } + } + p++; + } + for(yy = 0; yy < size; yy++) { + png_write_row(png_ptr, row); + } + } + /* bottom margin */ + fillRow(row, realwidth, bg_color); + for(y = 0; y < margin * size; y++) { + png_write_row(png_ptr, row); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + fclose(fp); + free(row); + free(palette); + + return 0; +#else + fputs("PNG output is disabled at compile time. No output generated.\n", stderr); + return 0; +#endif +} + +static int writeEPS(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y, yy; + int realwidth; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + /* EPS file header */ + fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n" + "%%%%BoundingBox: 0 0 %d %d\n" + "%%%%Pages: 1 1\n" + "%%%%EndComments\n", realwidth, realwidth); + /* draw point */ + fprintf(fp, "/p { " + "moveto " + "0 1 rlineto " + "1 0 rlineto " + "0 -1 rlineto " + "fill " + "} bind def\n"); + /* set color */ + fprintf(fp, "gsave\n"); + fprintf(fp, "%f %f %f setrgbcolor\n", + (float)bg_color[0] / 255, + (float)bg_color[1] / 255, + (float)bg_color[2] / 255); + fprintf(fp, "%d %d scale\n", realwidth, realwidth); + fprintf(fp, "0 0 p\ngrestore\n"); + fprintf(fp, "%f %f %f setrgbcolor\n", + (float)fg_color[0] / 255, + (float)fg_color[1] / 255, + (float)fg_color[2] / 255); + fprintf(fp, "%d %d scale\n", size, size); + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + yy = (margin + qrcode->width - y - 1); + + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + fprintf(fp, "%d %d p ", margin + x, yy); + } + } + } + + fprintf(fp, "\n%%%%EOF\n"); + fclose(fp); + + return 0; +} + +static void writeSVG_drawModules(FILE *fp, int x, int y, int width, const char* col, float opacity) +{ + if(svg_path) { + fprintf(fp, "M%d,%dh%d", x, y, width); + } else { + if(fg_color[3] != 255) { + fprintf(fp, "\t\t\t\n", + x, y, width, col, opacity ); + } else { + fprintf(fp, "\t\t\t\n", + x, y, width, col ); + } + } +} + +static int writeSVG(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y, x0, pen; + int symwidth, realwidth; + float scale; + char fg[7], bg[7]; + float fg_opacity; + float bg_opacity; + + fp = openFile(outfile); + + scale = dpi * INCHES_PER_METER / 100.0; + + symwidth = qrcode->width + margin * 2; + realwidth = symwidth * size; + + snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1], fg_color[2]); + snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1], bg_color[2]); + fg_opacity = (float)fg_color[3] / 255; + bg_opacity = (float)bg_color[3] / 255; + + /* XML declaration */ + if (!inline_svg) + fputs( "\n", fp ); + + /* DTD + No document type specified because "while a DTD is provided in [the SVG] + specification, the use of DTDs for validating XML documents is known to + be problematic. In particular, DTDs do not handle namespaces gracefully. + It is *not* recommended that a DOCTYPE declaration be included in SVG + documents." + http://www.w3.org/TR/2003/REC-SVG11-20030114/intro.html#Namespace + */ + + /* Vanity remark */ + fprintf(fp, "\n", QRcode_APIVersionString()); + + /* SVG code start */ + fprintf(fp, + "\n", + realwidth / scale, realwidth / scale, symwidth, symwidth + ); + + /* Make named group */ + fputs("\t\n", fp); + + /* Make solid background */ + if(bg_color[3] != 255) { + fprintf(fp, "\t\t\n", symwidth, symwidth, bg, bg_opacity); + } else { + fprintf(fp, "\t\t\n", symwidth, symwidth, bg); + } + + if(svg_path) { + if(fg_color[3] != 255) { + fprintf(fp, "\t\t\n", margin, margin); + } + + /* Write data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + + if( !rle ) { + /* no RLE */ + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + writeSVG_drawModules(fp, x, y, 1, fg, fg_opacity); + } + } + } else { + /* simple RLE */ + pen = 0; + x0 = 0; + for(x = 0; x < qrcode->width; x++) { + if( !pen ) { + pen = *(row+x)&0x1; + x0 = x; + } else if(!(*(row+x)&0x1)) { + writeSVG_drawModules(fp, x0, y, x-x0, fg, fg_opacity); + pen = 0; + } + } + if( pen ) { + writeSVG_drawModules(fp, x0, y, qrcode->width - x0, fg, fg_opacity); + } + } + } + + if(svg_path) { + fputs("\"/>\n", fp); + } else { + /* Close QR data viewbox */ + fputs("\t\t\n", fp); + } + + /* Close group */ + fputs("\t\n", fp); + + /* Close SVG code */ + fputs("\n", fp); + fclose(fp); + + return 0; +} + +static int writeXPM(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + int x, xx, y, yy, realwidth, realmargin; + char *row; + char fg[7], bg[7]; + unsigned char *p; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + realmargin = margin * size; + + row = malloc((size_t)realwidth + 1); + if (!row ) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1], fg_color[2]); + snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1], bg_color[2]); + + fputs("/* XPM */\n", fp); + fputs("static const char *const qrcode_xpm[] = {\n", fp); + fputs("/* width height ncolors chars_per_pixel */\n", fp); + fprintf(fp, "\"%d %d 2 1\",\n", realwidth, realwidth); + + fputs("/* colors */\n", fp); + fprintf(fp, "\"F c #%s\",\n", fg); + fprintf(fp, "\"B c #%s\",\n", bg); + + fputs("/* pixels */\n", fp); + memset(row, 'B', (size_t)realwidth); + row[realwidth] = '\0'; + + for (y = 0; y < realmargin; y++) { + fprintf(fp, "\"%s\",\n", row); + } + + p = qrcode->data; + for (y = 0; y < qrcode->width; y++) { + for (yy = 0; yy < size; yy++) { + fputs("\"", fp); + + for (x = 0; x < margin; x++) { + for (xx = 0; xx < size; xx++) { + fputs("B", fp); + } + } + + for (x = 0; x < qrcode->width; x++) { + for (xx = 0; xx < size; xx++) { + if (p[(y * qrcode->width) + x] & 0x1) { + fputs("F", fp); + } else { + fputs("B", fp); + } + } + } + + for (x = 0; x < margin; x++) { + for (xx = 0; xx < size; xx++) { + fputs("B", fp); + } + } + + fputs("\",\n", fp); + } + } + + for (y = 0; y < realmargin; y++) { + fprintf(fp, "\"%s\"%s\n", row, y < (size - 1) ? "," : "};"); + } + + free(row); + fclose(fp); + + return 0; +} + +static void writeANSI_margin(FILE* fp, int realwidth, + char* buffer, const char* white, int white_s ) +{ + int y; + + strncpy(buffer, white, (size_t)white_s); + memset(buffer + white_s, ' ', (size_t)realwidth * 2); + strcpy(buffer + white_s + realwidth * 2, "\033[0m\n"); // reset to default colors + for(y = 0; y < margin; y++ ){ + fputs(buffer, fp); + } +} + +static int writeANSI(const QRcode *qrcode, const char *outfile) +{ + FILE *fp; + unsigned char *row, *p; + int x, y; + int realwidth; + int last; + + const char *white, *black; + char *buffer; + int white_s, black_s, buffer_s; + + if(image_type == ANSI256_TYPE){ + /* codes for 256 color compatible terminals */ + white = "\033[48;5;231m"; + white_s = 11; + black = "\033[48;5;16m"; + black_s = 10; + } else { + white = "\033[47m"; + white_s = 5; + black = "\033[40m"; + black_s = 5; + } + + size = 1; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * size; + buffer_s = (realwidth * white_s) * 2; + buffer = (char *)malloc((size_t)buffer_s); + if(buffer == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + /* top margin */ + writeANSI_margin(fp, realwidth, buffer, white, white_s); + + /* data */ + p = qrcode->data; + for(y = 0; y < qrcode->width; y++) { + row = (p+(y*qrcode->width)); + + memset(buffer, 0, (size_t)buffer_s); + strncpy(buffer, white, (size_t)white_s); + for(x = 0; x < margin; x++ ){ + strncat(buffer, " ", 2); + } + last = 0; + + for(x = 0; x < qrcode->width; x++) { + if(*(row+x)&0x1) { + if( last != 1 ){ + strncat(buffer, black, (size_t)black_s); + last = 1; + } + } else if( last != 0 ){ + strncat(buffer, white, (size_t)white_s); + last = 0; + } + strncat(buffer, " ", 2); + } + + if( last != 0 ){ + strncat(buffer, white, (size_t)white_s); + } + for(x = 0; x < margin; x++ ){ + strncat(buffer, " ", 2); + } + strncat(buffer, "\033[0m\n", 5); + fputs(buffer, fp); + } + + /* bottom margin */ + writeANSI_margin(fp, realwidth, buffer, white, white_s); + + fclose(fp); + free(buffer); + + return 0; +} + +static void writeUTF8_margin(FILE* fp, int realwidth, const char* white, + const char *reset, const char* full) +{ + int x, y; + + for (y = 0; y < margin/2; y++) { + fputs(white, fp); + for (x = 0; x < realwidth; x++) + fputs(full, fp); + fputs(reset, fp); + fputc('\n', fp); + } +} + +static int writeUTF8(const QRcode *qrcode, const char *outfile, int use_ansi, int invert) +{ + FILE *fp; + int x, y; + int realwidth; + const char *white, *reset; + const char *empty, *lowhalf, *uphalf, *full; + + empty = " "; + lowhalf = "\342\226\204"; + uphalf = "\342\226\200"; + full = "\342\226\210"; + + if (invert) { + const char *tmp; + + tmp = empty; + empty = full; + full = tmp; + + tmp = lowhalf; + lowhalf = uphalf; + uphalf = tmp; + } + + if (use_ansi){ + if (use_ansi == 2) { + white = "\033[38;5;231m\033[48;5;16m"; + } else { + white = "\033[40;37;1m"; + } + reset = "\033[0m"; + } else { + white = ""; + reset = ""; + } + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2); + + /* top margin */ + writeUTF8_margin(fp, realwidth, white, reset, full); + + /* data */ + for(y = 0; y < qrcode->width; y += 2) { + unsigned char *row1, *row2; + row1 = qrcode->data + y*qrcode->width; + row2 = row1 + qrcode->width; + + fputs(white, fp); + + for (x = 0; x < margin; x++) { + fputs(full, fp); + } + + for (x = 0; x < qrcode->width; x++) { + if(row1[x] & 1) { + if(y < qrcode->width - 1 && row2[x] & 1) { + fputs(empty, fp); + } else { + fputs(lowhalf, fp); + } + } else if(y < qrcode->width - 1 && row2[x] & 1) { + fputs(uphalf, fp); + } else { + fputs(full, fp); + } + } + + for (x = 0; x < margin; x++) + fputs(full, fp); + + fputs(reset, fp); + fputc('\n', fp); + } + + /* bottom margin */ + writeUTF8_margin(fp, realwidth, white, reset, full); + + fclose(fp); + + return 0; +} + +static void writeASCII_margin(FILE* fp, int realwidth, char* buffer, int invert) +{ + int y, h; + + h = margin; + + memset(buffer, (invert?'#':' '), (size_t)realwidth); + buffer[realwidth] = '\n'; + buffer[realwidth + 1] = '\0'; + for(y = 0; y < h; y++ ){ + fputs(buffer, fp); + } +} + +static int writeASCII(const QRcode *qrcode, const char *outfile, int invert) +{ + FILE *fp; + unsigned char *row; + int x, y; + int realwidth; + char *buffer, *p; + int buffer_s; + char black = '#'; + char white = ' '; + + if(invert) { + black = ' '; + white = '#'; + } + + size = 1; + + fp = openFile(outfile); + + realwidth = (qrcode->width + margin * 2) * 2; + buffer_s = realwidth + 2; + buffer = (char *)malloc((size_t)buffer_s); + if(buffer == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + /* top margin */ + writeASCII_margin(fp, realwidth, buffer, invert); + + /* data */ + for(y = 0; y < qrcode->width; y++) { + row = qrcode->data+(y*qrcode->width); + p = buffer; + + memset(p, white, (size_t)margin * 2); + p += margin * 2; + + for(x = 0; x < qrcode->width; x++) { + if(row[x]&0x1) { + *p++ = black; + *p++ = black; + } else { + *p++ = white; + *p++ = white; + } + } + + memset(p, white, (size_t)margin * 2); + p += margin * 2; + *p++ = '\n'; + *p++ = '\0'; + fputs( buffer, fp ); + } + + /* bottom margin */ + writeASCII_margin(fp, realwidth, buffer, invert); + + fclose(fp); + free(buffer); + + return 0; +} + +static QRcode *encode(const unsigned char *intext, int length) +{ + QRcode *code; + + if(micro) { + if(eightbit) { + code = QRcode_encodeDataMQR(length, intext, version, level); + } else { + code = QRcode_encodeStringMQR((char *)intext, version, level, hint, casesensitive); + } + } else if(eightbit) { + code = QRcode_encodeData(length, intext, version, level); + } else { + code = QRcode_encodeString((char *)intext, version, level, hint, casesensitive); + } + + return code; +} + +static void qrencode(const unsigned char *intext, int length, const char *outfile) +{ + QRcode *qrcode; + + qrcode = encode(intext, length); + if(qrcode == NULL) { + if(errno == ERANGE) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + } else { + perror("Failed to encode the input data"); + } + exit(EXIT_FAILURE); + } + if(strict_versioning && version > 0 && qrcode->version != version) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + exit(EXIT_FAILURE); + } + + if(verbose) { + fprintf(stderr, "File: %s, Version: %d\n", (outfile!=NULL)?outfile:"(stdout)", qrcode->version); + } + + switch(image_type) { + case PNG_TYPE: + case PNG32_TYPE: + writePNG(qrcode, outfile, image_type); + break; + case EPS_TYPE: + writeEPS(qrcode, outfile); + break; + case SVG_TYPE: + writeSVG(qrcode, outfile); + break; + case XPM_TYPE: + writeXPM(qrcode, outfile); + break; + case ANSI_TYPE: + case ANSI256_TYPE: + writeANSI(qrcode, outfile); + break; + case ASCIIi_TYPE: + writeASCII(qrcode, outfile, 1); + break; + case ASCII_TYPE: + writeASCII(qrcode, outfile, 0); + break; + case UTF8_TYPE: + writeUTF8(qrcode, outfile, 0, 0); + break; + case ANSIUTF8_TYPE: + writeUTF8(qrcode, outfile, 1, 0); + break; + case ANSI256UTF8_TYPE: + writeUTF8(qrcode, outfile, 2, 0); + break; + case UTF8i_TYPE: + writeUTF8(qrcode, outfile, 0, 1); + break; + case ANSIUTF8i_TYPE: + writeUTF8(qrcode, outfile, 1, 1); + break; + default: + fprintf(stderr, "Unknown image type.\n"); + exit(EXIT_FAILURE); + } + + QRcode_free(qrcode); +} + +static QRcode_List *encodeStructured(const unsigned char *intext, int length) +{ + QRcode_List *list; + + if(eightbit) { + list = QRcode_encodeDataStructured(length, intext, version, level); + } else { + list = QRcode_encodeStringStructured((char *)intext, version, level, hint, casesensitive); + } + + return list; +} + +static void qrencodeStructured(const unsigned char *intext, int length, const char *outfile) +{ + QRcode_List *qrlist, *p; + char filename[FILENAME_MAX]; + char *base, *q, *suffix = NULL; + const char *type_suffix; + int i = 1; + size_t suffix_size; + + switch(image_type) { + case PNG_TYPE: + type_suffix = ".png"; + break; + case EPS_TYPE: + type_suffix = ".eps"; + break; + case SVG_TYPE: + type_suffix = ".svg"; + break; + case XPM_TYPE: + type_suffix = ".xpm"; + break; + case ANSI_TYPE: + case ANSI256_TYPE: + case ASCII_TYPE: + case UTF8_TYPE: + case ANSIUTF8_TYPE: + case UTF8i_TYPE: + case ANSIUTF8i_TYPE: + type_suffix = ".txt"; + break; + default: + fprintf(stderr, "Unknown image type.\n"); + exit(EXIT_FAILURE); + } + + if(outfile == NULL) { + fprintf(stderr, "An output filename must be specified to store the structured images.\n"); + exit(EXIT_FAILURE); + } + base = strdup(outfile); + if(base == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + suffix_size = strlen(type_suffix); + if(strlen(base) > suffix_size) { + q = base + strlen(base) - suffix_size; + if(strcasecmp(type_suffix, q) == 0) { + suffix = strdup(q); + *q = '\0'; + } + } + + qrlist = encodeStructured(intext, length); + if(qrlist == NULL) { + if(errno == ERANGE) { + fprintf(stderr, "Failed to encode the input data: Input data too large\n"); + } else { + perror("Failed to encode the input data"); + } + exit(EXIT_FAILURE); + } + + for(p = qrlist; p != NULL; p = p->next) { + if(p->code == NULL) { + fprintf(stderr, "Failed to encode the input data.\n"); + exit(EXIT_FAILURE); + } + if(suffix) { + snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix); + } else { + snprintf(filename, FILENAME_MAX, "%s-%02d", base, i); + } + + if(verbose) { + fprintf(stderr, "File: %s, Version: %d\n", filename, p->code->version); + } + + switch(image_type) { + case PNG_TYPE: + case PNG32_TYPE: + writePNG(p->code, filename, image_type); + break; + case EPS_TYPE: + writeEPS(p->code, filename); + break; + case SVG_TYPE: + writeSVG(p->code, filename); + break; + case XPM_TYPE: + writeXPM(p->code, filename); + break; + case ANSI_TYPE: + case ANSI256_TYPE: + writeANSI(p->code, filename); + break; + case ASCIIi_TYPE: + writeASCII(p->code, filename, 1); + break; + case ASCII_TYPE: + writeASCII(p->code, filename, 0); + break; + case UTF8_TYPE: + writeUTF8(p->code, filename, 0, 0); + break; + case ANSIUTF8_TYPE: + writeUTF8(p->code, filename, 0, 0); + break; + case ANSI256UTF8_TYPE: + writeUTF8(p->code, filename, 0, 0); + break; + case UTF8i_TYPE: + writeUTF8(p->code, filename, 0, 1); + break; + case ANSIUTF8i_TYPE: + writeUTF8(p->code, filename, 0, 1); + break; + + default: + fprintf(stderr, "Unknown image type.\n"); + exit(EXIT_FAILURE); + } + i++; + } + + free(base); + if(suffix) { + free(suffix); + } + + QRcode_List_free(qrlist); +} + +int main(int argc, char **argv) +{ + int opt, lindex = -1; + char *outfile = NULL, *infile = NULL; + unsigned char *intext = NULL; + int length = 0; + FILE *fp; + + while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) { + switch(opt) { + case 'h': + if(lindex == 0) { + usage(1, 1, EXIT_SUCCESS); + } else { + usage(1, 0, EXIT_SUCCESS); + } + exit(EXIT_SUCCESS); + case 'o': + outfile = optarg; + break; + case 'r': + infile = optarg; + break; + case 's': + size = atoi(optarg); + if(size <= 0) { + fprintf(stderr, "Invalid size: %d\n", size); + exit(EXIT_FAILURE); + } + break; + case 'v': + version = atoi(optarg); + if(version < 0) { + fprintf(stderr, "Invalid version: %d\n", version); + exit(EXIT_FAILURE); + } + break; + case 'l': + switch(*optarg) { + case 'l': + case 'L': + level = QR_ECLEVEL_L; + break; + case 'm': + case 'M': + level = QR_ECLEVEL_M; + break; + case 'q': + case 'Q': + level = QR_ECLEVEL_Q; + break; + case 'h': + case 'H': + level = QR_ECLEVEL_H; + break; + default: + fprintf(stderr, "Invalid level: %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'm': + margin = atoi(optarg); + if(margin < 0) { + fprintf(stderr, "Invalid margin: %d\n", margin); + exit(EXIT_FAILURE); + } + break; + case 'd': + dpi = atoi(optarg); + if( dpi < 0 ) { + fprintf(stderr, "Invalid DPI: %d\n", dpi); + exit(EXIT_FAILURE); + } + break; + case 't': + if(strcasecmp(optarg, "png32") == 0) { + image_type = PNG32_TYPE; + } else if(strcasecmp(optarg, "png") == 0) { + image_type = PNG_TYPE; + } else if(strcasecmp(optarg, "eps") == 0) { + image_type = EPS_TYPE; + } else if(strcasecmp(optarg, "svg") == 0) { + image_type = SVG_TYPE; + } else if(strcasecmp(optarg, "xpm") == 0) { + image_type = XPM_TYPE; + } else if(strcasecmp(optarg, "ansi") == 0) { + image_type = ANSI_TYPE; + } else if(strcasecmp(optarg, "ansi256") == 0) { + image_type = ANSI256_TYPE; + } else if(strcasecmp(optarg, "asciii") == 0) { + image_type = ASCIIi_TYPE; + } else if(strcasecmp(optarg, "ascii") == 0) { + image_type = ASCII_TYPE; + } else if(strcasecmp(optarg, "utf8") == 0) { + image_type = UTF8_TYPE; + } else if(strcasecmp(optarg, "ansiutf8") == 0) { + image_type = ANSIUTF8_TYPE; + } else if(strcasecmp(optarg, "ansi256utf8") == 0) { + image_type = ANSI256UTF8_TYPE; + } else if(strcasecmp(optarg, "utf8i") == 0) { + image_type = UTF8i_TYPE; + } else if(strcasecmp(optarg, "ansiutf8i") == 0) { + image_type = ANSIUTF8i_TYPE; + } else { + fprintf(stderr, "Invalid image type: %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'S': + structured = 1; + break; + case 'k': + hint = QR_MODE_KANJI; + break; + case 'c': + casesensitive = 1; + break; + case 'i': + casesensitive = 0; + break; + case '8': + eightbit = 1; + break; + case 'M': + micro = 1; + break; + case 'f': + if(color_set(fg_color, optarg)) { + fprintf(stderr, "Invalid foreground color value.\n"); + exit(EXIT_FAILURE); + } + break; + case 'b': + if(color_set(bg_color, optarg)) { + fprintf(stderr, "Invalid background color value.\n"); + exit(EXIT_FAILURE); + } + break; + case 'V': + usage(0, 0, EXIT_SUCCESS); + exit(EXIT_SUCCESS); + case 0: + break; + default: + fprintf(stderr, "Try \"qrencode --help\" for more information.\n"); + exit(EXIT_FAILURE); + } + } + + if(argc == 1) { + usage(1, 0, EXIT_FAILURE); + exit(EXIT_FAILURE); + } + + if(outfile == NULL && image_type == PNG_TYPE) { + fprintf(stderr, "No output filename is given.\n"); + exit(EXIT_FAILURE); + } + + if(optind < argc) { + intext = (unsigned char *)argv[optind]; + length = strlen((char *)intext); + } + if(intext == NULL) { + fp = infile == NULL ? stdin : fopen(infile,"r"); + if(fp == 0) { + fprintf(stderr, "Cannot read input file %s.\n", infile); + exit(EXIT_FAILURE); + } + intext = readFile(fp,&length); + + } + + if(micro && version > MQRSPEC_VERSION_MAX) { + fprintf(stderr, "Version number should be less or equal to %d.\n", MQRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } else if(!micro && version > QRSPEC_VERSION_MAX) { + fprintf(stderr, "Version number should be less or equal to %d.\n", QRSPEC_VERSION_MAX); + exit(EXIT_FAILURE); + } + + if(margin < 0) { + if(micro) { + margin = 2; + } else { + margin = 4; + } + } + + if(micro) { + if(structured) { + fprintf(stderr, "Micro QR Code does not support structured symbols.\n"); + exit(EXIT_FAILURE); + } + } + + if(structured) { + if(version == 0) { + fprintf(stderr, "Version number must be specified to encode structured symbols.\n"); + exit(EXIT_FAILURE); + } + qrencodeStructured(intext, length, outfile); + } else { + qrencode(intext, length, outfile); + } + + return 0; +} diff --git a/datafile/qrencode/qrencode.c b/datafile/qrencode/qrencode.c new file mode 100644 index 0000000..2cb9ca8 --- /dev/null +++ b/datafile/qrencode/qrencode.c @@ -0,0 +1,938 @@ +/* + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" +#include "rsecc.h" +#include "split.h" +#include "mask.h" +#include "mmask.h" + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + int eccLength; + unsigned char *data; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc) +{ + block->dataLength = dl; + block->data = data; + block->eccLength = el; + block->ecc = ecc; + + RSECC_encode((size_t)dl, (size_t)el, data, ecc); +} + +static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsigned char *ecc) +{ + int i; + RSblock *block; + unsigned char *dp, *ep; + int el, dl; + + dl = QRspec_rsDataCodes1(spec); + el = QRspec_rsEccCodes1(spec); + + block = blocks; + dp = data; + ep = ecc; + for(i = 0; i < QRspec_rsBlockNum1(spec); i++) { + RSblock_initBlock(block, dl, dp, el, ep); + dp += dl; + ep += el; + block++; + } + + if(QRspec_rsBlockNum2(spec) == 0) return 0; + + dl = QRspec_rsDataCodes2(spec); + el = QRspec_rsEccCodes2(spec); + for(i = 0; i < QRspec_rsBlockNum2(spec); i++) { + RSblock_initBlock(block, dl, dp, el, ep); + dp += dl; + ep += el; + block++; + } + + return 0; +} + +STATIC_IN_RELEASE void QRraw_free(QRRawCode *raw); +STATIC_IN_RELEASE QRRawCode *QRraw_new(QRinput *input) +{ + QRRawCode *raw; + int spec[5], ret; + + raw = (QRRawCode *)malloc(sizeof(QRRawCode)); + if(raw == NULL) return NULL; + + raw->datacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + + QRspec_getEccSpec(input->version, input->level, spec); + + raw->version = input->version; + raw->b1 = QRspec_rsBlockNum1(spec); + raw->dataLength = QRspec_rsDataLength(spec); + raw->eccLength = QRspec_rsEccLength(spec); + raw->ecccode = (unsigned char *)malloc((size_t)raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->blocks = QRspec_rsBlockNum(spec); + raw->rsblock = (RSblock *)calloc((size_t)(raw->blocks), sizeof(RSblock)); + if(raw->rsblock == NULL) { + QRraw_free(raw); + return NULL; + } + ret = RSblock_init(raw->rsblock, spec, raw->datacode, raw->ecccode); + if(ret < 0) { + QRraw_free(raw); + return NULL; + } + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +STATIC_IN_RELEASE unsigned char QRraw_getCode(QRRawCode *raw) +{ + int col, row; + unsigned char ret; + + if(raw->count < raw->dataLength) { + row = raw->count % raw->blocks; + col = raw->count / raw->blocks; + if(col >= raw->rsblock[0].dataLength) { + row += raw->b1; + } + ret = raw->rsblock[row].data[col]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + row = (raw->count - raw->dataLength) % raw->blocks; + col = (raw->count - raw->dataLength) / raw->blocks; + ret = raw->rsblock[row].ecc[col]; + } else { + return 0; + } + raw->count++; + return ret; +} + +STATIC_IN_RELEASE void QRraw_free(QRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +STATIC_IN_RELEASE void MQRraw_free(MQRRawCode *raw); +STATIC_IN_RELEASE MQRRawCode *MQRraw_new(QRinput *input) +{ + MQRRawCode *raw; + + raw = (MQRRawCode *)malloc(sizeof(MQRRawCode)); + if(raw == NULL) return NULL; + + raw->version = input->version; + raw->dataLength = MQRspec_getDataLength(input->version, input->level); + raw->eccLength = MQRspec_getECCLength(input->version, input->level); + raw->oddbits = raw->dataLength * 8 - MQRspec_getDataLengthBit(input->version, input->level); + raw->datacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + raw->ecccode = (unsigned char *)malloc((size_t)raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->rsblock = (RSblock *)calloc(1, sizeof(RSblock)); + if(raw->rsblock == NULL) { + MQRraw_free(raw); + return NULL; + } + + RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode); + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +STATIC_IN_RELEASE unsigned char MQRraw_getCode(MQRRawCode *raw) +{ + unsigned char ret; + + if(raw->count < raw->dataLength) { + ret = raw->datacode[raw->count]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + ret = raw->ecccode[raw->count - raw->dataLength]; + } else { + return 0; + } + raw->count++; + return ret; +} + +STATIC_IN_RELEASE void MQRraw_free(MQRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + + +/****************************************************************************** + * Frame filling + *****************************************************************************/ + +typedef struct { + int width; + unsigned char *frame; + int x, y; + int dir; + int bit; + int mqr; +} FrameFiller; + +static void FrameFiller_set(FrameFiller *filler, int width, unsigned char *frame, int mqr) +{ + filler->width = width; + filler->frame = frame; + filler->x = width - 1; + filler->y = width - 1; + filler->dir = -1; + filler->bit = -1; + filler->mqr = mqr; +} + +static unsigned char *FrameFiller_next(FrameFiller *filler) +{ + unsigned char *p; + int x, y, w; + + if(filler->bit == -1) { + filler->bit = 0; + return filler->frame + filler->y * filler->width + filler->x; + } + + x = filler->x; + y = filler->y; + p = filler->frame; + w = filler->width; + + if(filler->bit == 0) { + x--; + filler->bit++; + } else { + x++; + y += filler->dir; + filler->bit--; + } + + if(filler->dir < 0) { + if(y < 0) { + y = 0; + x -= 2; + filler->dir = 1; + if(!filler->mqr && x == 6) { + x--; + y = 9; + } + } + } else if(y == w) { + y = w - 1; + x -= 2; + filler->dir = -1; + if(!filler->mqr && x == 6) { + x--; + y -= 8; + } + } + if(x < 0 || y < 0) return NULL; + + filler->x = x; + filler->y = y; + + if(p[y * w + x] & 0x80) { + // This tail recursion could be optimized. + return FrameFiller_next(filler); + } + return &p[y * w + x]; +} + +#ifdef WITH_TESTS +unsigned char *FrameFiller_test(int version) +{ + int width; + unsigned char *frame, *p; + int i, length; + FrameFiller filler; + + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) return NULL; + FrameFiller_set(&filler, width, frame, 0); + length = QRspec_getDataLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getECCLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getRemainder(version); + for(i = 0; i < length; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) { + free(frame); + return NULL; + } + *p = (unsigned char)(i & 0x7f) | 0x80; + } + return frame; +} + +unsigned char *FrameFiller_testMQR(int version) +{ + int width; + unsigned char *frame, *p; + int i, length; + FrameFiller filler; + + width = MQRspec_getWidth(version); + frame = MQRspec_newFrame(version); + if(frame == NULL) return NULL; + FrameFiller_set(&filler, width, frame, 1); + length = MQRspec_getDataLengthBit(version, QR_ECLEVEL_L) + + MQRspec_getECCLength(version, QR_ECLEVEL_L) * 8; + for(i = 0; i < length; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) { + fprintf(stderr, "Frame filler run over the frame!\n"); + return frame; + } + *p = (unsigned char)(i & 0x7f) | 0x80; + } + return frame; +} +#endif + + +/****************************************************************************** + * QR-code encoding + *****************************************************************************/ + +STATIC_IN_RELEASE QRcode *QRcode_new(int version, int width, unsigned char *data) +{ + QRcode *qrcode; + + qrcode = (QRcode *)malloc(sizeof(QRcode)); + if(qrcode == NULL) return NULL; + + qrcode->version = version; + qrcode->width = width; + qrcode->data = data; + + return qrcode; +} + +void QRcode_free(QRcode *qrcode) +{ + if(qrcode != NULL) { + free(qrcode->data); + free(qrcode); + } +} + +STATIC_IN_RELEASE QRcode *QRcode_encodeMask(QRinput *input, int mask) +{ + int width, version; + QRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + int i, j; + QRcode *qrcode = NULL; + FrameFiller filler; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(!(input->level >= QR_ECLEVEL_L && input->level <= QR_ECLEVEL_H)) { + errno = EINVAL; + return NULL; + } + + raw = QRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) { + QRraw_free(raw); + return NULL; + } + FrameFiller_set(&filler, width, frame, 0); + + /* interleaved data and ecc codes */ + for(i = 0; i < raw->dataLength; i++) { + code = QRraw_getCode(raw); + bit = 0x80; + for(j = 0; j < 8; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = ((bit & code) != 0); + bit = bit >> 1; + } + } + for(i = 0; i < raw->eccLength; i++) { + code = QRraw_getCode(raw); + bit = 0x80; + for(j = 0; j < 8; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + QRraw_free(raw); + raw = NULL; + /* remainder bits */ + j = QRspec_getRemainder(version); + for(i = 0; i < j; i++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02; + } + + /* masking */ + if(mask == -2) { // just for debug purpose + masked = (unsigned char *)malloc((size_t)(width * width)); + memcpy(masked, frame, (size_t)(width * width)); + } else if(mask < 0) { + masked = Mask_mask(width, frame, input->level); + } else { + masked = Mask_makeMask(width, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + qrcode = QRcode_new(version, width, masked); + if(qrcode == NULL) { + free(masked); + } + +EXIT: + QRraw_free(raw); + free(frame); + return qrcode; +} + +STATIC_IN_RELEASE QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask) +{ + int width, version; + MQRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + int i, j, length; + QRcode *qrcode = NULL; + FrameFiller filler; + + if(!input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version <= 0 || input->version > MQRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(!(input->level >= QR_ECLEVEL_L && input->level <= QR_ECLEVEL_Q)) { + errno = EINVAL; + return NULL; + } + + raw = MQRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = MQRspec_getWidth(version); + frame = MQRspec_newFrame(version); + if(frame == NULL) { + MQRraw_free(raw); + return NULL; + } + FrameFiller_set(&filler, width, frame, 1); + + /* interleaved data and ecc codes */ + for(i = 0; i < raw->dataLength; i++) { + code = MQRraw_getCode(raw); + bit = 0x80; + if(raw->oddbits && i == raw->dataLength - 1) { + length = raw->oddbits; + } else { + length = 8; + } + for(j = 0; j < length; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = ((bit & code) != 0); + bit = bit >> 1; + } + } + for(i = 0; i < raw->eccLength; i++) { + code = MQRraw_getCode(raw); + bit = 0x80; + length = 8; + for(j = 0; j < length; j++) { + p = FrameFiller_next(&filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + MQRraw_free(raw); + raw = NULL; + + /* masking */ + if(mask == -2) { // just for debug purpose + masked = (unsigned char *)malloc((size_t)(width * width)); + memcpy(masked, frame, (size_t)(width * width)); + } else if(mask < 0) { + masked = MMask_mask(version, frame, input->level); + } else { + masked = MMask_makeMask(version, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + + qrcode = QRcode_new(version, width, masked); + if(qrcode == NULL) { + free(masked); + } + +EXIT: + MQRraw_free(raw); + free(frame); + return qrcode; +} + +QRcode *QRcode_encodeInput(QRinput *input) +{ + if(input->mqr) { + return QRcode_encodeMaskMQR(input, -1); + } else { + return QRcode_encodeMask(input, -1); + } +} + +static QRcode *QRcode_encodeStringReal(const char *string, int version, QRecLevel level, int mqr, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode *code; + int ret; + + if(string == NULL) { + errno = EINVAL; + return NULL; + } + if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = Split_splitStringToQRinput(string, input, hint, casesensitive); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + return QRcode_encodeStringReal(string, version, level, 0, hint, casesensitive); +} + +QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + int i; + + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX ; i++) { + QRcode *code = QRcode_encodeStringReal(string, i, level, 1, hint, casesensitive); + if(code != NULL) return code; + } + + return NULL; +} + +static QRcode *QRcode_encodeDataReal(const unsigned char *data, int length, int version, QRecLevel level, int mqr) +{ + QRinput *input; + QRcode *code; + int ret; + + if(data == NULL || length == 0) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = QRinput_append(input, QR_MODE_8, length, data); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level) +{ + return QRcode_encodeDataReal(data, size, version, level, 0); +} + +QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataReal((unsigned char *)string, (int)strlen(string), version, level, 0); +} + +QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level) +{ + int i; + + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX; i++) { + QRcode *code = QRcode_encodeDataReal(data, size, i, level, 1); + if(code != NULL) return code; + } + + return NULL; +} + +QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level) +{ + int i; + + if(string == NULL) { + errno = EINVAL; + return NULL; + } + if(version == 0) { + version = 1; + } + for(i = version; i <= MQRSPEC_VERSION_MAX; i++) { + QRcode *code = QRcode_encodeDataReal((unsigned char *)string, (int)strlen(string), i, level, 1); + if(code != NULL) return code; + } + + return NULL; +} + + +/****************************************************************************** + * Structured QR-code encoding + *****************************************************************************/ + +static QRcode_List *QRcode_List_newEntry(void) +{ + QRcode_List *entry; + + entry = (QRcode_List *)malloc(sizeof(QRcode_List)); + if(entry == NULL) return NULL; + + entry->next = NULL; + entry->code = NULL; + + return entry; +} + +static void QRcode_List_freeEntry(QRcode_List *entry) +{ + if(entry != NULL) { + QRcode_free(entry->code); + free(entry); + } +} + +void QRcode_List_free(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist, *next; + + while(list != NULL) { + next = list->next; + QRcode_List_freeEntry(list); + list = next; + } +} + +int QRcode_List_size(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist; + int size = 0; + + while(list != NULL) { + size++; + list = list->next; + } + + return size; +} + +#if 0 +static unsigned char QRcode_parity(const char *str, int size) +{ + unsigned char parity = 0; + int i; + + for(i = 0; i < size; i++) { + parity ^= str[i]; + } + + return parity; +} +#endif + +QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s) +{ + QRcode_List *head = NULL; + QRcode_List *tail = NULL; + QRcode_List *entry; + QRinput_InputList *list = s->head; + + while(list != NULL) { + if(head == NULL) { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + head = entry; + tail = head; + } else { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + tail->next = entry; + tail = tail->next; + } + tail->code = QRcode_encodeInput(list->input); + if(tail->code == NULL) { + goto ABORT; + } + list = list->next; + } + + return head; +ABORT: + QRcode_List_free(head); + return NULL; +} + +static QRcode_List *QRcode_encodeInputToStructured(QRinput *input) +{ + QRinput_Struct *s; + QRcode_List *codes; + + s = QRinput_splitQRinputToStruct(input); + if(s == NULL) return NULL; + + codes = QRcode_encodeInputStructured(s); + QRinput_Struct_free(s); + + return codes; +} + +static QRcode_List *QRcode_encodeDataStructuredReal( + int size, const unsigned char *data, + int version, QRecLevel level, + int eightbit, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode_List *codes; + int ret; + + if(version <= 0) { + errno = EINVAL; + return NULL; + } + if(!eightbit && (hint != QR_MODE_8 && hint != QR_MODE_KANJI)) { + errno = EINVAL; + return NULL; + } + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, size, data); + } else { + ret = Split_splitStringToQRinput((char *)data, input, hint, casesensitive); + } + if(ret < 0) { + QRinput_free(input); + return NULL; + } + codes = QRcode_encodeInputToStructured(input); + QRinput_free(input); + + return codes; +} + +QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level) { + return QRcode_encodeDataStructuredReal(size, data, version, level, 1, QR_MODE_NUL, 0); +} + +QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level) { + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructured((int)strlen(string), (unsigned char *)string, version, level); +} + +QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructuredReal((int)strlen(string), (unsigned char *)string, version, level, 0, hint, casesensitive); +} + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version) +{ + if(major_version != NULL) { + *major_version = MAJOR_VERSION; + } + if(minor_version != NULL) { + *minor_version = MINOR_VERSION; + } + if(micro_version != NULL) { + *micro_version = MICRO_VERSION; + } +} + +char *QRcode_APIVersionString(void) +{ + return VERSION; +} + +void QRcode_clearCache(void) +{ + return; +} diff --git a/datafile/qrencode/qrencode.h b/datafile/qrencode/qrencode.h new file mode 100644 index 0000000..1a934cc --- /dev/null +++ b/datafile/qrencode/qrencode.h @@ -0,0 +1,568 @@ +/** + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** \mainpage + * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D + * symbology. + * + * \section encoding Encoding + * + * There are two methods to encode data: encoding a string/data or + * encoding a structured data. + * + * \subsection encoding-string Encoding a string/data + * You can encode a string by calling QRcode_encodeString(). + * The given string is parsed automatically and encoded. If you want to encode + * data that can be represented as a C string style (NUL terminated), you can + * simply use this way. + * + * If the input data contains Kanji (Shift-JIS) characters and you want to + * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint. + * Otherwise, all of non-alphanumeric characters are encoded as 8-bit data. + * If you want to encode a whole string in 8-bit mode, you can use + * QRcode_encodeString8bit() instead. + * + * Please note that a C string can not contain NUL characters. If your data + * contains NUL, you must use QRcode_encodeData(). + * + * \subsection encoding-input Encoding a structured data + * You can construct a structured input data manually. If the structure of the + * input data is known, you can use this method. + * At first, create a ::QRinput object by QRinput_new(). Then add input data + * to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput() + * to encode the QRinput data. + * You can reuse the QRinput object again to encode it in other symbols with + * different parameters. + * + * \section result Result + * The encoded symbol is generated as a ::QRcode object. It will contain its + * version number, the width of the symbol, and an array represents the symbol. + * See ::QRcode for the details. You can free the object by QRcode_free(). + * + * Please note that the version of the result may be larger than specified. + * In such cases, the input data would be too large to be encoded in a + * symbol of the specified version. + * + * \section structured Structured append + * Libqrencode can generate "Structured-appended" symbols that enables to split + * a large data set into mulitple QR codes. A QR code reader concatenates + * multiple QR code symbols into a string. + * Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured() + * to generate structured-appended symbols. This functions returns an instance + * of ::QRcode_List. The returned list is a singly-linked list of QRcode: you + * can retrieve each QR code in this way: + * + * \code + * QRcode_List *qrcodes; + * QRcode_List *entry; + * QRcode *qrcode; + * + * qrcodes = QRcode_encodeStringStructured(...); + * entry = qrcodes; + * while(entry != NULL) { + * qrcode = entry->code; + * // do something + * entry = entry->next; + * } + * QRcode_List_free(entry); + * \endcode + * + * Instead of using auto-parsing functions, you can construct your own + * structured input. At first, instantiate an object of ::QRinput_Struct + * by calling QRinput_Struct_new(). This object can hold multiple ::QRinput, + * and one QR code is generated for a ::QRinput. + * QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct + * object. In order to generate structured-appended symbols, it is required to + * embed headers to each symbol. You can use + * QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate + * headers to each symbol. You should call this function just once before + * encoding symbols. + */ + +#ifndef QRENCODE_H +#define QRENCODE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encoding mode. + */ +typedef enum { + QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only + QR_MODE_NUM = 0, ///< Numeric mode + QR_MODE_AN, ///< Alphabet-numeric mode + QR_MODE_8, ///< 8-bit data mode + QR_MODE_KANJI, ///< Kanji (shift-jis) mode + QR_MODE_STRUCTURE, ///< Internal use only + QR_MODE_ECI, ///< ECI mode + QR_MODE_FNC1FIRST, ///< FNC1, first position + QR_MODE_FNC1SECOND, ///< FNC1, second position +} QRencodeMode; + +/** + * Level of error correction. + */ +typedef enum { + QR_ECLEVEL_L = 0, ///< lowest + QR_ECLEVEL_M, + QR_ECLEVEL_Q, + QR_ECLEVEL_H ///< highest +} QRecLevel; + +/** + * Maximum version (size) of QR-code symbol. + */ +#define QRSPEC_VERSION_MAX 40 + +/** + * Maximum version (size) of QR-code symbol. + */ +#define MQRSPEC_VERSION_MAX 4 + + +/****************************************************************************** + * Input data (qrinput.c) + *****************************************************************************/ + +/** + * Singly linked list to contain input strings. An instance of this class + * contains its version and error correction level too. It is required to + * set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(), + * or use QRinput_new2() to instantiate an object. + */ +typedef struct _QRinput QRinput; + +/** + * Instantiate an input data object. The version is set to 0 (auto-select) + * and the error correction level is set to QR_ECLEVEL_L. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput *QRinput_new(void); + +/** + * Instantiate an input data object. + * @param version version number. + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_new2(int version, QRecLevel level); + +/** + * Instantiate an input data object. Object's Micro QR Code flag is set. + * Unlike with full-sized QR Code, version number must be specified (>0). + * @param version version number (1--4). + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_newMQR(int version, QRecLevel level); + +/** + * Append data to an input object. + * The data is copied and appended to the input object. + * @param input input object. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data); + +/** + * Append ECI header. + * @param input input object. + * @param ecinum ECI indicator number (0 - 999999) + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum); + +/** + * Get current version. + * @param input input object. + * @return current version. + */ +extern int QRinput_getVersion(QRinput *input); + +/** + * Set version of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersion(QRinput *input, int version); + +/** + * Get current error correction level. + * @param input input object. + * @return Current error correcntion level. + */ +extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input); + +/** + * Set error correction level of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level); + +/** + * Set version and error correction level of the QR code at once. + * This function is recommened for Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level); + +/** + * Free the input object. + * All of data chunks in the input object are freed too. + * @param input input object. + */ +extern void QRinput_free(QRinput *input); + +/** + * Validate the input data. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 invalid arguments. + */ +extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data); + +/** + * Set of QRinput for structured symbols. + */ +typedef struct _QRinput_Struct QRinput_Struct; + +/** + * Instantiate a set of input data object. + * @return an instance of QRinput_Struct. On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_Struct_new(void); + +/** + * Set parity of structured symbols. + * @param s structured input object. + * @param parity parity of s. + */ +extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity); + +/** + * Append a QRinput object to the set. QRinput created by QRinput_newMQR() + * will be rejected. + * @warning never append the same QRinput object twice or more. + * @param s structured input object. + * @param input an input object. + * @retval >0 number of input objects in the structure. + * @retval -1 an error occurred. See Exceptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid arguments. + */ +extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input); + +/** + * Free all of QRinput in the set. + * @param s a structured input object. + */ +extern void QRinput_Struct_free(QRinput_Struct *s); + +/** + * Split a QRinput to QRinput_Struct. It calculates a parity, set it, then + * insert structured-append headers. QRinput created by QRinput_newMQR() will + * be rejected. + * @param input input object. Version number and error correction level must be + * set. + * @return a set of input data. On error, NULL is returned, and errno is set + * to indicate the error. See Exceptions for the details. + * @throw ERANGE input data is too large. + * @throw EINVAL invalid input data. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input); + +/** + * Insert structured-append headers to the input structure. It calculates + * a parity and set it if the parity is not set yet. + * @param s input structure + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory. + */ +extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s); + +/** + * Set FNC1-1st position flag. + */ +extern int QRinput_setFNC1First(QRinput *input); + +/** + * Set FNC1-2nd position flag and application identifier. + */ +extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid); + +/****************************************************************************** + * QRcode output (qrencode.c) + *****************************************************************************/ + +/** + * QRcode class. + * Symbol data is represented as an array contains width*width uchars. + * Each uchar represents a module (dot). If the less significant bit of + * the uchar is 1, the corresponding module is black. The other bits are + * meaningless for usual applications, but here its specification is described. + * + * @verbatim + MSB 76543210 LSB + |||||||`- 1=black/0=white + ||||||`-- 1=ecc/0=data code area + |||||`--- format information + ||||`---- version information + |||`----- timing pattern + ||`------ alignment pattern + |`------- finder pattern and separator + `-------- non-data modules (format, timing, etc.) + @endverbatim + */ +typedef struct { + int version; ///< version of the symbol + int width; ///< width of the symbol + unsigned char *data; ///< symbol data +} QRcode; + +/** + * Singly-linked list of QRcode. Used to represent a structured symbols. + * A list is terminated with NULL. + */ +typedef struct _QRcode_List { + QRcode *code; + struct _QRcode_List *next; +} QRcode_List; + +/** + * Create a symbol from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param input input data. + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode *QRcode_encodeInput(QRinput *input); + +/** + * Create a symbol from the string. The library automatically parses the input + * string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeString(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeString(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Micro QR Code version of QRcode_encodeString8bit(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level); + +/** + * Encode byte stream (may include '\0') in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input data. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeData(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Free the instance of QRcode class. + * @param qrcode an instance of QRcode class. + */ +extern void QRcode_free(QRcode *qrcode); + +/** + * Create structured symbols from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param s input data, structured. + * @return a singly-linked list of QRcode. + */ +extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s); + +/** + * Create structured symbols from the string. The library automatically parses + * the input string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level); + +/** + * Create structured symbols from byte stream (may include '\0'). Wholde data + * are encoded in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input dat. + * @param version version of the symbol. + * @param level error correction level. + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Return the number of symbols included in a QRcode_List. + * @param qrlist a head entry of a QRcode_List. + * @return number of symbols in the list. + */ +extern int QRcode_List_size(QRcode_List *qrlist); + +/** + * Free the QRcode_List. + * @param qrlist a head entry of a QRcode_List. + */ +extern void QRcode_List_free(QRcode_List *qrlist); + + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +/** + * Return a string that identifies the library version. + * @param major_version major version number + * @param minor_version minor version number + * @param micro_version micro version number + */ +extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version); + +/** + * Return a string that identifies the library version. + * @return a string identifies the library version. The string is held by the + * library. Do NOT free it. + */ +extern char *QRcode_APIVersionString(void); + +/** + * @deprecated + */ +#ifndef _MSC_VER +extern void QRcode_clearCache(void) __attribute__ ((deprecated)); +#else +extern void QRcode_clearCache(void); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* QRENCODE_H */ diff --git a/datafile/qrencode/qrencode_inner.h b/datafile/qrencode/qrencode_inner.h new file mode 100644 index 0000000..2ea54f5 --- /dev/null +++ b/datafile/qrencode/qrencode_inner.h @@ -0,0 +1,88 @@ +/** + * qrencode - QR Code encoder + * + * Header for test use + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRENCODE_INNER_H +#define QRENCODE_INNER_H + +/** + * This header file includes definitions for test use. + */ + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + int eccLength; + unsigned char *data; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +extern QRRawCode *QRraw_new(QRinput *input); +extern unsigned char QRraw_getCode(QRRawCode *raw); +extern void QRraw_free(QRRawCode *raw); + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +extern MQRRawCode *MQRraw_new(QRinput *input); +extern unsigned char MQRraw_getCode(MQRRawCode *raw); +extern void MQRraw_free(MQRRawCode *raw); + +/****************************************************************************** + * Frame filling + *****************************************************************************/ +extern unsigned char *FrameFiller_test(int version); +extern unsigned char *FrameFiller_testMQR(int version); + +/****************************************************************************** + * QR-code encoding + *****************************************************************************/ +extern QRcode *QRcode_encodeMask(QRinput *input, int mask); +extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask); +extern QRcode *QRcode_new(int version, int width, unsigned char *data); + +#endif /* QRENCODE_INNER_H */ diff --git a/datafile/qrencode/qrinput.c b/datafile/qrencode/qrinput.c new file mode 100644 index 0000000..34bedc2 --- /dev/null +++ b/datafile/qrencode/qrinput.c @@ -0,0 +1,1639 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" + +/****************************************************************************** + * Utilities + *****************************************************************************/ +int QRinput_isSplittableMode(QRencodeMode mode) +{ + return (mode >= QR_MODE_NUM && mode <= QR_MODE_KANJI); +} + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ + +static QRinput_List *QRinput_List_newEntry(QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + if(QRinput_check(mode, size, data)) { + errno = EINVAL; + return NULL; + } + + entry = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(entry == NULL) return NULL; + + entry->mode = mode; + entry->size = size; + entry->data = NULL; + if(size > 0) { + entry->data = (unsigned char *)malloc((size_t)size); + if(entry->data == NULL) { + free(entry); + return NULL; + } + memcpy(entry->data, data, (size_t)size); + } + entry->bstream = NULL; + entry->next = NULL; + + return entry; +} + +static void QRinput_List_freeEntry(QRinput_List *entry) +{ + if(entry != NULL) { + free(entry->data); + BitStream_free(entry->bstream); + free(entry); + } +} + +static QRinput_List *QRinput_List_dup(QRinput_List *entry) +{ + QRinput_List *n; + + n = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(n == NULL) return NULL; + + n->mode = entry->mode; + n->size = entry->size; + n->data = (unsigned char *)malloc((size_t)n->size); + if(n->data == NULL) { + free(n); + return NULL; + } + memcpy(n->data, entry->data, (size_t)entry->size); + n->bstream = NULL; + n->next = NULL; + + return n; +} + +/****************************************************************************** + * Input Data + *****************************************************************************/ + +QRinput *QRinput_new(void) +{ + return QRinput_new2(0, QR_ECLEVEL_L); +} + +QRinput *QRinput_new2(int version, QRecLevel level) +{ + QRinput *input; + + if(version < 0 || version > QRSPEC_VERSION_MAX || level < 0 || level > QR_ECLEVEL_H) { + errno = EINVAL; + return NULL; + } + + input = (QRinput *)malloc(sizeof(QRinput)); + if(input == NULL) return NULL; + + input->head = NULL; + input->tail = NULL; + input->version = version; + input->level = level; + input->mqr = 0; + input->fnc1 = 0; + + return input; +} + +QRinput *QRinput_newMQR(int version, QRecLevel level) +{ + QRinput *input; + + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if((MQRspec_getECCLength(version, level) == 0)) goto INVALID; + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + input->mqr = 1; + + return input; + +INVALID: + errno = EINVAL; + return NULL; +} + +int QRinput_getVersion(QRinput *input) +{ + return input->version; +} + +int QRinput_setVersion(QRinput *input, int version) +{ + if(input->mqr || version < 0 || version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return -1; + } + + input->version = version; + + return 0; +} + +QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input) +{ + return input->level; +} + +int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level) +{ + if(input->mqr || level > QR_ECLEVEL_H) { + errno = EINVAL; + return -1; + } + + input->level = level; + + return 0; +} + +int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level) +{ + if(input->mqr) { + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if((MQRspec_getECCLength(version, level) == 0)) goto INVALID; + } else { + if(version < 0 || version > QRSPEC_VERSION_MAX) goto INVALID; + if(level > QR_ECLEVEL_H) goto INVALID; + } + + input->version = version; + input->level = level; + + return 0; + +INVALID: + errno = EINVAL; + return -1; +} + +static void QRinput_appendEntry(QRinput *input, QRinput_List *entry) +{ + if(input->tail == NULL) { + input->head = entry; + input->tail = entry; + } else { + input->tail->next = entry; + input->tail = entry; + } + entry->next = NULL; +} + +int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + entry = QRinput_List_newEntry(mode, size, data); + if(entry == NULL) { + return -1; + } + + QRinput_appendEntry(input, entry); + + return 0; +} + +/** + * Insert a structured-append header to the head of the input data. + * @param input input data. + * @param size number of structured symbols. + * @param number index number of the symbol. (1 <= number <= size) + * @param parity parity among input data. (NOTE: each symbol of a set of structured symbols has the same parity data) + * @retval 0 success. + * @retval -1 error occurred and errno is set to indeicate the error. See Execptions for the details. + * @throw EINVAL invalid parameter. + * @throw ENOMEM unable to allocate memory. + */ +STATIC_IN_RELEASE int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int number, unsigned char parity) +{ + QRinput_List *entry; + unsigned char buf[3]; + + if(size > MAX_STRUCTURED_SYMBOLS) { + errno = EINVAL; + return -1; + } + if(number <= 0 || number > size) { + errno = EINVAL; + return -1; + } + + buf[0] = (unsigned char)size; + buf[1] = (unsigned char)number; + buf[2] = parity; + entry = QRinput_List_newEntry(QR_MODE_STRUCTURE, 3, buf); + if(entry == NULL) { + return -1; + } + + entry->next = input->head; + input->head = entry; + + return 0; +} + +int QRinput_appendECIheader(QRinput *input, unsigned int ecinum) +{ + unsigned char data[4]; + + if(ecinum > 999999) { + errno = EINVAL; + return -1; + } + + /* We manually create byte array of ecinum because + (unsigned char *)&ecinum may cause bus error on some architectures, */ + data[0] = ecinum & 0xff; + data[1] = (ecinum >> 8) & 0xff; + data[2] = (ecinum >> 16) & 0xff; + data[3] = (ecinum >> 24) & 0xff; + return QRinput_append(input, QR_MODE_ECI, 4, data); +} + +void QRinput_free(QRinput *input) +{ + QRinput_List *list, *next; + + if(input != NULL) { + list = input->head; + while(list != NULL) { + next = list->next; + QRinput_List_freeEntry(list); + list = next; + } + free(input); + } +} + +static unsigned char QRinput_calcParity(QRinput *input) +{ + unsigned char parity = 0; + QRinput_List *list; + int i; + + list = input->head; + while(list != NULL) { + if(list->mode != QR_MODE_STRUCTURE) { + for(i = list->size-1; i >= 0; i--) { + parity ^= list->data[i]; + } + } + list = list->next; + } + + return parity; +} + +QRinput *QRinput_dup(QRinput *input) +{ + QRinput *n; + QRinput_List *list, *e; + + if(input->mqr) { + n = QRinput_newMQR(input->version, input->level); + } else { + n = QRinput_new2(input->version, input->level); + } + if(n == NULL) return NULL; + + list = input->head; + while(list != NULL) { + e = QRinput_List_dup(list); + if(e == NULL) { + QRinput_free(n); + return NULL; + } + QRinput_appendEntry(n, e); + list = list->next; + } + + return n; +} + +/****************************************************************************** + * Numeric data + *****************************************************************************/ + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeNum(int size, const char *data) +{ + int i; + + for(i = 0; i < size; i++) { + if(data[i] < '0' || data[i] > '9') + return -1; + } + + return 0; +} + +/** + * Estimate the length of the encoded bit stream of numeric data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsModeNum(int size) +{ + int w; + int bits; + + w = size / 3; + bits = w * 10; + switch(size - w * 3) { + case 1: + bits += 4; + break; + case 2: + bits += 7; + break; + default: + break; + } + + return bits; +} + +/** + * Convert the number data and append to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeModeNum(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, i, ret; + unsigned int val; + + if(mqr) { + if(version > 1) { + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_NUM); + if(ret < 0) return -1; + } + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_NUM, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_NUM); + if(ret < 0) return -1; + + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_NUM, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + words = entry->size / 3; + for(i = 0; i < words; i++) { + val = (unsigned int)(entry->data[i*3 ] - '0') * 100; + val += (unsigned int)(entry->data[i*3+1] - '0') * 10; + val += (unsigned int)(entry->data[i*3+2] - '0'); + + ret = BitStream_appendNum(bstream, 10, val); + if(ret < 0) return -1; + } + + if(entry->size - words * 3 == 1) { + val = (unsigned int)(entry->data[words*3] - '0'); + ret = BitStream_appendNum(bstream, 4, val); + if(ret < 0) return -1; + } else if(entry->size - words * 3 == 2) { + val = (unsigned int)(entry->data[words*3 ] - '0') * 10; + val += (unsigned int)(entry->data[words*3+1] - '0'); + ret = BitStream_appendNum(bstream, 7, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * Alphabet-numeric data + *****************************************************************************/ + +const signed char QRinput_anTable[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeAn(int size, const char *data) +{ + int i; + + for(i = 0; i < size; i++) { + if(QRinput_lookAnTable(data[i]) < 0) + return -1; + } + + return 0; +} + +/** + * Estimate the length of the encoded bit stream of alphabet-numeric data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsModeAn(int size) +{ + int w; + int bits; + + w = size / 2; + bits = w * 11; + if(size & 1) { + bits += 6; + } + + return bits; +} + +/** + * Convert the alphabet-numeric data and append to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid version. + */ +static int QRinput_encodeModeAn(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, i, ret; + unsigned int val; + + if(mqr) { + if(version < 2) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_AN); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_AN, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_AN); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_AN, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + words = entry->size / 2; + for(i = 0; i < words; i++) { + val = (unsigned int)QRinput_lookAnTable(entry->data[i*2 ]) * 45; + val += (unsigned int)QRinput_lookAnTable(entry->data[i*2+1]); + + ret = BitStream_appendNum(bstream, 11, val); + if(ret < 0) return -1; + } + + if(entry->size & 1) { + val = (unsigned int)QRinput_lookAnTable(entry->data[words * 2]); + + ret = BitStream_appendNum(bstream, 6, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * 8 bit data + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream of 8 bit data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsMode8(int size) +{ + return size * 8; +} + +/** + * Convert the 8bits data and append to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeMode8(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int ret; + + if(mqr) { + if(version < 3) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_8); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_8, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_8); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_8, version), (unsigned int)entry->size); + if(ret < 0) return -1; + } + + ret = BitStream_appendBytes(bstream, (size_t)entry->size, entry->data); + if(ret < 0) return -1; + + return 0; +} + + +/****************************************************************************** + * Kanji data + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream of kanji data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsModeKanji(int size) +{ + return (size / 2) * 13; +} + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeKanji(int size, const unsigned char *data) +{ + int i; + unsigned int val; + + if(size & 1) + return -1; + + for(i = 0; i < size; i+=2) { + val = ((unsigned int)data[i] << 8) | data[i+1]; + if(val < 0x8140 || (val > 0x9ffc && val < 0xe040) || val > 0xebbf) { + return -1; + } + } + + return 0; +} + +/** + * Convert the kanji data and append to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid version. + */ +static int QRinput_encodeModeKanji(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int ret, i; + unsigned int val, h; + + if(mqr) { + if(version < 2) { + errno = ERANGE; + return -1; + } + ret = BitStream_appendNum(bstream, (size_t)(version - 1), MQRSPEC_MODEID_KANJI); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)MQRspec_lengthIndicator(QR_MODE_KANJI, version), (unsigned int)entry->size/2); + if(ret < 0) return -1; + } else { + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_KANJI); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, (size_t)QRspec_lengthIndicator(QR_MODE_KANJI, version), (unsigned int)entry->size/2); + if(ret < 0) return -1; + } + + for(i = 0; i < entry->size; i+=2) { + val = ((unsigned int)entry->data[i] << 8) | entry->data[i+1]; + if(val <= 0x9ffc) { + val -= 0x8140; + } else { + val -= 0xc140; + } + h = (val >> 8) * 0xc0; + val = (val & 0xff) + h; + + ret = BitStream_appendNum(bstream, 13, val); + if(ret < 0) return -1; + } + + return 0; +} + +/****************************************************************************** + * Structured Symbol + *****************************************************************************/ + +/** + * Convert a structure symbol code and append to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid entry. + */ +static int QRinput_encodeModeStructure(QRinput_List *entry, BitStream *bstream, int mqr) +{ + int ret; + + if(mqr) { + errno = EINVAL; + return -1; + } + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_STRUCTURE); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 4, entry->data[1] - 1U); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 4, entry->data[0] - 1U); + if(ret < 0) return -1; + ret = BitStream_appendNum(bstream, 8, entry->data[2]); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * FNC1 + *****************************************************************************/ + +static int QRinput_checkModeFNC1Second(int size) +{ + if(size != 1) return -1; + + /* No data check required. */ + + return 0; +} + +static int QRinput_encodeModeFNC1Second(QRinput_List *entry, BitStream *bstream) +{ + int ret; + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_FNC1SECOND); + if(ret < 0) return -1; + + ret = BitStream_appendBytes(bstream, 1, entry->data); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * ECI header + *****************************************************************************/ +static unsigned int QRinput_decodeECIfromByteArray(unsigned char *data) +{ + int i; + unsigned int ecinum; + + ecinum = 0; + for(i = 0; i < 4; i++) { + ecinum = ecinum << 8; + ecinum |= data[3-i]; + } + + return ecinum; +} + +static int QRinput_estimateBitsModeECI(unsigned char *data) +{ + unsigned int ecinum; + + ecinum = QRinput_decodeECIfromByteArray(data); + + /* See Table 4 of JISX 0510:2004 pp.17. */ + if(ecinum < 128) { + return MODE_INDICATOR_SIZE + 8; + } else if(ecinum < 16384) { + return MODE_INDICATOR_SIZE + 16; + } else { + return MODE_INDICATOR_SIZE + 24; + } +} + +static int QRinput_encodeModeECI(QRinput_List *entry, BitStream *bstream) +{ + int ret, words; + unsigned int ecinum, code; + + ecinum = QRinput_decodeECIfromByteArray(entry->data); + + /* See Table 4 of JISX 0510:2004 pp.17. */ + if(ecinum < 128) { + words = 1; + code = ecinum; + } else if(ecinum < 16384) { + words = 2; + code = 0x8000 + ecinum; + } else { + words = 3; + code = 0xc0000 + ecinum; + } + + ret = BitStream_appendNum(bstream, 4, QRSPEC_MODEID_ECI); + if(ret < 0) return -1; + + ret = BitStream_appendNum(bstream, (size_t)words * 8, code); + if(ret < 0) return -1; + + return 0; +} + +/****************************************************************************** + * Validation + *****************************************************************************/ + +int QRinput_check(QRencodeMode mode, int size, const unsigned char *data) +{ + if((mode == QR_MODE_FNC1FIRST && size < 0) || size <= 0) return -1; + + switch(mode) { + case QR_MODE_NUM: + return QRinput_checkModeNum(size, (const char *)data); + case QR_MODE_AN: + return QRinput_checkModeAn(size, (const char *)data); + case QR_MODE_KANJI: + return QRinput_checkModeKanji(size, data); + case QR_MODE_8: + return 0; + case QR_MODE_STRUCTURE: + return 0; + case QR_MODE_ECI: + return 0; + case QR_MODE_FNC1FIRST: + return 0; + case QR_MODE_FNC1SECOND: + return QRinput_checkModeFNC1Second(size); + case QR_MODE_NUL: + break; + } + + return -1; +} + +/****************************************************************************** + * Estimation of the bit length + *****************************************************************************/ + +/** + * Estimate the length of the encoded bit stream on the current version. + * @param entry + * @param version version of the symbol + * @param mqr + * @return number of bits + */ +static int QRinput_estimateBitStreamSizeOfEntry(QRinput_List *entry, int version, int mqr) +{ + int bits = 0; + int l, m; + int num; + + if(version == 0) version = 1; + + switch(entry->mode) { + case QR_MODE_NUM: + bits = QRinput_estimateBitsModeNum(entry->size); + break; + case QR_MODE_AN: + bits = QRinput_estimateBitsModeAn(entry->size); + break; + case QR_MODE_8: + bits = QRinput_estimateBitsMode8(entry->size); + break; + case QR_MODE_KANJI: + bits = QRinput_estimateBitsModeKanji(entry->size); + break; + case QR_MODE_STRUCTURE: + return STRUCTURE_HEADER_SIZE; + case QR_MODE_ECI: + bits = QRinput_estimateBitsModeECI(entry->data); + break; + case QR_MODE_FNC1FIRST: + return MODE_INDICATOR_SIZE; + case QR_MODE_FNC1SECOND: + return MODE_INDICATOR_SIZE + 8; + default: + return 0; + } + + if(mqr) { + l = MQRspec_lengthIndicator(entry->mode, version); + m = version - 1; + bits += l + m; + } else { + l = QRspec_lengthIndicator(entry->mode, version); + m = 1 << l; + if(entry->mode == QR_MODE_KANJI) { + num = (entry->size/2 + m - 1) / m; + } else { + num = (entry->size + m - 1) / m; + } + + bits += num * (MODE_INDICATOR_SIZE + l); + } + + return bits; +} + +/** + * Estimate the length of the encoded bit stream of the data. + * @param input input data + * @param version version of the symbol + * @return number of bits + */ +STATIC_IN_RELEASE int QRinput_estimateBitStreamSize(QRinput *input, int version) +{ + QRinput_List *list; + int bits = 0; + + list = input->head; + while(list != NULL) { + bits += QRinput_estimateBitStreamSizeOfEntry(list, version, input->mqr); + list = list->next; + } + + return bits; +} + +/** + * Estimate the required version number of the symbol. + * @param input input data + * @return required version number or -1 for failure. + */ +STATIC_IN_RELEASE int QRinput_estimateVersion(QRinput *input) +{ + int bits; + int version, prev; + + version = 0; + do { + prev = version; + bits = QRinput_estimateBitStreamSize(input, prev); + version = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if(prev == 0 && version > 1) { + version--; + } + } while (version > prev); + + return version; +} + +/** + * Return required length in bytes for specified mode, version and bits. + * @param mode + * @param version + * @param bits + * @return required length of code words in bytes. + */ +STATIC_IN_RELEASE int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits) +{ + int payload, size, chunks, remain, maxsize; + + payload = bits - 4 - QRspec_lengthIndicator(mode, version); + switch(mode) { + case QR_MODE_NUM: + chunks = payload / 10; + remain = payload - chunks * 10; + size = chunks * 3; + if(remain >= 7) { + size += 2; + } else if(remain >= 4) { + size += 1; + } + break; + case QR_MODE_AN: + chunks = payload / 11; + remain = payload - chunks * 11; + size = chunks * 2; + if(remain >= 6) size++; + break; + case QR_MODE_8: + size = payload / 8; + break; + case QR_MODE_KANJI: + size = (payload / 13) * 2; + break; + case QR_MODE_STRUCTURE: + size = payload / 8; + break; + default: + size = 0; + break; + } + maxsize = QRspec_maximumWords(mode, version); + if(size < 0) size = 0; + if(maxsize > 0 && size > maxsize) size = maxsize; + + return size; +} + +/****************************************************************************** + * Data conversion + *****************************************************************************/ + +/** + * Convert the input data in the data chunk and append to a bit stream. + * @param entry + * @param bstream + * @return number of bits (>0) or -1 for failure. + */ +static int QRinput_encodeBitStream(QRinput_List *entry, BitStream *bstream, int version, int mqr) +{ + int words, ret; + QRinput_List *st1 = NULL, *st2 = NULL; + int prevsize; + + prevsize = (int)BitStream_size(bstream); + + if(mqr) { + words = MQRspec_maximumWords(entry->mode, version); + } else { + words = QRspec_maximumWords(entry->mode, version); + } + if(words != 0 && entry->size > words) { + st1 = QRinput_List_newEntry(entry->mode, words, entry->data); + if(st1 == NULL) goto ABORT; + st2 = QRinput_List_newEntry(entry->mode, entry->size - words, &entry->data[words]); + if(st2 == NULL) goto ABORT; + + ret = QRinput_encodeBitStream(st1, bstream, version, mqr); + if(ret < 0) goto ABORT; + ret = QRinput_encodeBitStream(st2, bstream, version, mqr); + if(ret < 0) goto ABORT; + + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + } else { + ret = 0; + switch(entry->mode) { + case QR_MODE_NUM: + ret = QRinput_encodeModeNum(entry, bstream, version, mqr); + break; + case QR_MODE_AN: + ret = QRinput_encodeModeAn(entry, bstream, version, mqr); + break; + case QR_MODE_8: + ret = QRinput_encodeMode8(entry, bstream, version, mqr); + break; + case QR_MODE_KANJI: + ret = QRinput_encodeModeKanji(entry, bstream, version, mqr); + break; + case QR_MODE_STRUCTURE: + ret = QRinput_encodeModeStructure(entry, bstream, mqr); + break; + case QR_MODE_ECI: + ret = QRinput_encodeModeECI(entry, bstream); + break; + case QR_MODE_FNC1SECOND: + ret = QRinput_encodeModeFNC1Second(entry, bstream); + break; + default: + break; + } + if(ret < 0) return -1; + } + + return (int)BitStream_size(bstream) - prevsize; +ABORT: + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + return -1; +} + +/** + * Convert the input data to a bit stream. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_createBitStream(QRinput *input, BitStream *bstream) +{ + QRinput_List *list; + int bits, total = 0; + + list = input->head; + while(list != NULL) { + bits = QRinput_encodeBitStream(list, bstream, input->version, input->mqr); + if(bits < 0) return -1; + total += bits; + list = list->next; + } + + return total; +} + +/** + * Convert the input data to a bit stream. + * When the version number is given and that is not sufficient, it is increased + * automatically. + * @param input input data. + * @param bstream where the converted data is stored. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw ERANGE input data is too large. + */ +static int QRinput_convertData(QRinput *input, BitStream *bstream) +{ + int bits; + int ver; + + ver = QRinput_estimateVersion(input); + if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } + + for(;;) { + BitStream_reset(bstream); + bits = QRinput_createBitStream(input, bstream); + if(bits < 0) return -1; + ver = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } else { + break; + } + } + + return 0; +} + +/** + * Append padding bits for the input data. + * @param bstream Bitstream to be appended. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ERANGE input data is too large. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_appendPaddingBit(BitStream *bstream, QRinput *input) +{ + int bits, maxbits, words, maxwords, i, ret; + int padlen; + + bits = (int)BitStream_size(bstream); + maxwords = QRspec_getDataLength(input->version, input->level); + maxbits = maxwords * 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + if(maxbits - bits <= 4) { + return (int)BitStream_appendNum(bstream, (size_t)(maxbits - bits), 0); + } + + words = (bits + 4 + 7) / 8; + + ret = (int)BitStream_appendNum(bstream, (size_t)(words * 8 - bits), 0); + if(ret < 0) return ret; + + padlen = maxwords - words; + if(padlen > 0) { + for(i = 0; i < padlen; i++) { + ret = (int)BitStream_appendNum(bstream, 8, (i&1)?0x11:0xec); + if(ret < 0) { + return ret; + } + } + } + + return 0; +} + +/** + * Append padding bits for the input data - Micro QR Code version. + * @param bstream Bitstream to be appended. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ERANGE input data is too large. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_appendPaddingBitMQR(BitStream *bstream, QRinput *input) +{ + int bits, maxbits, words, maxwords, i, ret, termbits; + int padlen; + + bits = (int)BitStream_size(bstream); + maxbits = MQRspec_getDataLengthBit(input->version, input->level); + maxwords = maxbits / 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + termbits = input->version * 2 + 1; + + if(maxbits - bits <= termbits) { + return (int)BitStream_appendNum(bstream, (size_t)(maxbits - bits), 0); + } + + bits += termbits; + + words = (bits + 7) / 8; + if(maxbits - words * 8 > 0) { + termbits += words * 8 - bits; + if(words == maxwords) termbits += maxbits - words * 8; + } else { + termbits += words * 8 - bits; + } + ret = (int)BitStream_appendNum(bstream, (size_t)termbits, 0); + if(ret < 0) return ret; + + padlen = maxwords - words; + if(padlen > 0) { + for(i = 0; i < padlen; i++) { + ret = (int)BitStream_appendNum(bstream, 8, (i&1)?0x11:0xec); + if(ret < 0) return ret; + } + termbits = maxbits - maxwords * 8; + if(termbits > 0) { + ret = (int)BitStream_appendNum(bstream, (size_t)termbits, 0); + if(ret < 0) return ret; + } + } + + return 0; +} + +static int QRinput_insertFNC1Header(QRinput *input) +{ + QRinput_List *entry = NULL; + + if(input->fnc1 == 1) { + entry = QRinput_List_newEntry(QR_MODE_FNC1FIRST, 0, NULL); + } else if(input->fnc1 == 2) { + entry = QRinput_List_newEntry(QR_MODE_FNC1SECOND, 1, &(input->appid)); + } + if(entry == NULL) { + return -1; + } + + if(input->head->mode != QR_MODE_STRUCTURE && input->head->mode != QR_MODE_ECI) { + entry->next = input->head; + input->head = entry; + } else { + entry->next = input->head->next; + input->head->next = entry; + } + + return 0; +} + +/** + * Merge all bit streams in the input data. + * @param input input data. + * @return merged bit stream + */ + +STATIC_IN_RELEASE int QRinput_mergeBitStream(QRinput *input, BitStream *bstream) +{ + if(input->mqr) { + if(QRinput_createBitStream(input, bstream) < 0) { + return -1; + } + } else { + if(input->fnc1) { + if(QRinput_insertFNC1Header(input) < 0) { + return -1; + } + } + if(QRinput_convertData(input, bstream) < 0) { + return -1; + } + } + + return 0; +} + +/** + * Merge all bit streams in the input data and append padding bits + * @param input input data. + * @return padded merged bit stream + */ + +STATIC_IN_RELEASE int QRinput_getBitStream(QRinput *input, BitStream *bstream) +{ + int ret; + + ret = QRinput_mergeBitStream(input, bstream); + if(ret < 0) return -1; + + if(input->mqr) { + ret = QRinput_appendPaddingBitMQR(bstream, input); + } else { + ret = QRinput_appendPaddingBit(bstream, input); + } + if(ret < 0) return -1; + + return 0; +} + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ + +unsigned char *QRinput_getByteStream(QRinput *input) +{ + BitStream *bstream; + unsigned char *array; + int ret; + + bstream = BitStream_new(); + if(bstream == NULL) { + return NULL; + } + + ret = QRinput_getBitStream(input, bstream); + if(ret < 0) { + BitStream_free(bstream); + return NULL; + } + array = BitStream_toByte(bstream); + BitStream_free(bstream); + + return array; +} + +/****************************************************************************** + * Structured input data + *****************************************************************************/ + +static QRinput_InputList *QRinput_InputList_newEntry(QRinput *input) +{ + QRinput_InputList *entry; + + entry = (QRinput_InputList *)malloc(sizeof(QRinput_InputList)); + if(entry == NULL) return NULL; + + entry->input = input; + entry->next = NULL; + + return entry; +} + +static void QRinput_InputList_freeEntry(QRinput_InputList *entry) +{ + if(entry != NULL) { + QRinput_free(entry->input); + free(entry); + } +} + +QRinput_Struct *QRinput_Struct_new(void) +{ + QRinput_Struct *s; + + s = (QRinput_Struct *)malloc(sizeof(QRinput_Struct)); + if(s == NULL) return NULL; + + s->size = 0; + s->parity = -1; + s->head = NULL; + s->tail = NULL; + + return s; +} + +void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity) +{ + s->parity = (int)parity; +} + +int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input) +{ + QRinput_InputList *e; + + if(input->mqr) { + errno = EINVAL; + return -1; + } + + e = QRinput_InputList_newEntry(input); + if(e == NULL) return -1; + + s->size++; + if(s->tail == NULL) { + s->head = e; + s->tail = e; + } else { + s->tail->next = e; + s->tail = e; + } + + return s->size; +} + +void QRinput_Struct_free(QRinput_Struct *s) +{ + QRinput_InputList *list, *next; + + if(s != NULL) { + list = s->head; + while(list != NULL) { + next = list->next; + QRinput_InputList_freeEntry(list); + list = next; + } + free(s); + } +} + +static unsigned char QRinput_Struct_calcParity(QRinput_Struct *s) +{ + QRinput_InputList *list; + unsigned char parity = 0; + + list = s->head; + while(list != NULL) { + parity ^= QRinput_calcParity(list->input); + list = list->next; + } + + QRinput_Struct_setParity(s, parity); + + return parity; +} + +static int QRinput_List_shrinkEntry(QRinput_List *entry, int bytes) +{ + unsigned char *data; + + data = (unsigned char *)malloc((size_t)bytes); + if(data == NULL) return -1; + + memcpy(data, entry->data, (size_t)bytes); + free(entry->data); + entry->data = data; + entry->size = bytes; + + return 0; +} + +STATIC_IN_RELEASE int QRinput_splitEntry(QRinput_List *entry, int bytes) +{ + QRinput_List *e; + int ret; + + e = QRinput_List_newEntry(entry->mode, entry->size - bytes, entry->data + bytes); + if(e == NULL) { + return -1; + } + + ret = QRinput_List_shrinkEntry(entry, bytes); + if(ret < 0) { + QRinput_List_freeEntry(e); + return -1; + } + + e->next = entry->next; + entry->next = e; + + return 0; +} + +QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input) +{ + QRinput *p = NULL; + QRinput_Struct *s = NULL; + int bits, maxbits, nextbits, bytes, ret; + QRinput_List *list, *next, *prev; + BitStream *bstream = NULL; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + + s = QRinput_Struct_new(); + if(s == NULL) return NULL; + + input = QRinput_dup(input); + if(input == NULL) { + QRinput_Struct_free(s); + return NULL; + } + + QRinput_Struct_setParity(s, QRinput_calcParity(input)); + maxbits = QRspec_getDataLength(input->version, input->level) * 8 - STRUCTURE_HEADER_SIZE; + + if(maxbits <= 0) goto ABORT; + + bstream = BitStream_new(); + if(bstream == NULL) goto ABORT; + + bits = 0; + list = input->head; + prev = NULL; + while(list != NULL) { + nextbits = QRinput_estimateBitStreamSizeOfEntry(list, input->version, input->mqr); + if(bits + nextbits <= maxbits) { + BitStream_reset(bstream); + ret = QRinput_encodeBitStream(list, bstream, input->version, input->mqr); + if(ret < 0) goto ABORT; + bits += ret; + prev = list; + list = list->next; + } else { + bytes = QRinput_lengthOfCode(list->mode, input->version, maxbits - bits); + p = QRinput_new2(input->version, input->level); + if(p == NULL) goto ABORT; + if(bytes > 0) { + /* Splits this entry into 2 entries. */ + ret = QRinput_splitEntry(list, bytes); + if(ret < 0) { + QRinput_free(p); + goto ABORT; + } + /* First half is the tail of the current input. */ + next = list->next; + list->next = NULL; + /* Second half is the head of the next input, p.*/ + p->head = next; + /* Renew QRinput.tail. */ + p->tail = input->tail; + input->tail = list; + /* Point to the next entry. */ + prev = list; + list = next; + } else { + /* Current entry will go to the next input. */ + prev->next = NULL; + p->head = list; + p->tail = input->tail; + input->tail = prev; + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) { + QRinput_free(p); + goto ABORT; + } + input = p; + bits = 0; + } + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) goto ABORT; + if(s->size > MAX_STRUCTURED_SYMBOLS) { + errno = ERANGE; + QRinput_Struct_free(s); + BitStream_free(bstream); + return NULL; + } + ret = QRinput_Struct_insertStructuredAppendHeaders(s); + if(ret < 0) { + QRinput_Struct_free(s); + BitStream_free(bstream); + return NULL; + } + + BitStream_free(bstream); + return s; + +ABORT: + BitStream_free(bstream); + QRinput_free(input); + QRinput_Struct_free(s); + return NULL; +} + +int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s) +{ + int i; + QRinput_InputList *list; + + if(s->size == 1) { + return 0; + } + + if(s->parity < 0) { + QRinput_Struct_calcParity(s); + } + i = 1; + list = s->head; + while(list != NULL) { + if(QRinput_insertStructuredAppendHeader(list->input, s->size, i, s->parity)) + return -1; + i++; + list = list->next; + } + + return 0; +} + +/****************************************************************************** + * Extended encoding mode (FNC1 and ECI) + *****************************************************************************/ + +int QRinput_setFNC1First(QRinput *input) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 1; + + return 0; +} + +int QRinput_setFNC1Second(QRinput *input, unsigned char appid) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 2; + input->appid = appid; + + return 0; +} diff --git a/datafile/qrencode/qrinput.h b/datafile/qrencode/qrinput.h new file mode 100644 index 0000000..5892c48 --- /dev/null +++ b/datafile/qrencode/qrinput.h @@ -0,0 +1,124 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRINPUT_H +#define QRINPUT_H + +#include "qrencode.h" +#include "bitstream.h" + +int QRinput_isSplittableMode(QRencodeMode mode); + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ +typedef struct _QRinput_List QRinput_List; + +struct _QRinput_List { + QRencodeMode mode; + int size; ///< Size of data chunk (byte). + unsigned char *data; ///< Data chunk. + BitStream *bstream; + QRinput_List *next; +}; + +/****************************************************************************** + * Input Data + *****************************************************************************/ +struct _QRinput { + int version; + QRecLevel level; + QRinput_List *head; + QRinput_List *tail; + int mqr; + int fnc1; + unsigned char appid; +}; + +/****************************************************************************** + * Structured append input data + *****************************************************************************/ +typedef struct _QRinput_InputList QRinput_InputList; + +struct _QRinput_InputList { + QRinput *input; + QRinput_InputList *next; +}; + +struct _QRinput_Struct { + int size; ///< number of structured symbols + int parity; + QRinput_InputList *head; + QRinput_InputList *tail; +}; + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ +extern unsigned char *QRinput_getByteStream(QRinput *input); + + +extern int QRinput_estimateBitsModeNum(int size); +extern int QRinput_estimateBitsModeAn(int size); +extern int QRinput_estimateBitsMode8(int size); +extern int QRinput_estimateBitsModeKanji(int size); + +extern QRinput *QRinput_dup(QRinput *input); + +extern const signed char QRinput_anTable[128]; + +/** + * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19). + * @param __c__ character + * @return value + */ +#define QRinput_lookAnTable(__c__) \ + ((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__]) + +/** + * Length of a standard mode indicator in bits. + */ + +#define MODE_INDICATOR_SIZE 4 + +/** + * Length of a segment of structured-append header. + */ +#define STRUCTURE_HEADER_SIZE 20 + +/** + * Maximum number of symbols in a set of structured-appended symbols. + */ +#define MAX_STRUCTURED_SYMBOLS 16 + +#ifdef WITH_TESTS +extern int QRinput_mergeBitStream(QRinput *input, BitStream *bstream); +extern int QRinput_getBitStream(QRinput *input, BitStream *bstream); +extern int QRinput_estimateBitStreamSize(QRinput *input, int version); +extern int QRinput_splitEntry(QRinput_List *entry, int bytes); +extern int QRinput_estimateVersion(QRinput *input); +extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits); +extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity); +#endif + +#endif /* QRINPUT_H */ diff --git a/datafile/qrencode/qrspec.c b/datafile/qrencode/qrspec.c new file mode 100644 index 0000000..f3d3b2c --- /dev/null +++ b/datafile/qrencode/qrspec.c @@ -0,0 +1,514 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include + +#include "qrspec.h" +#include "qrinput.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; //< Edge length of the symbol + int words; //< Data capacity (bytes) + int remainder; //< Remainder bit (bits) + int ec[4]; //< Number of ECC code (bytes) +} QRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = { + { 0, 0, 0, { 0, 0, 0, 0}}, + { 21, 26, 0, { 7, 10, 13, 17}}, // 1 + { 25, 44, 7, { 10, 16, 22, 28}}, + { 29, 70, 7, { 15, 26, 36, 44}}, + { 33, 100, 7, { 20, 36, 52, 64}}, + { 37, 134, 7, { 26, 48, 72, 88}}, // 5 + { 41, 172, 7, { 36, 64, 96, 112}}, + { 45, 196, 0, { 40, 72, 108, 130}}, + { 49, 242, 0, { 48, 88, 132, 156}}, + { 53, 292, 0, { 60, 110, 160, 192}}, + { 57, 346, 0, { 72, 130, 192, 224}}, //10 + { 61, 404, 0, { 80, 150, 224, 264}}, + { 65, 466, 0, { 96, 176, 260, 308}}, + { 69, 532, 0, { 104, 198, 288, 352}}, + { 73, 581, 3, { 120, 216, 320, 384}}, + { 77, 655, 3, { 132, 240, 360, 432}}, //15 + { 81, 733, 3, { 144, 280, 408, 480}}, + { 85, 815, 3, { 168, 308, 448, 532}}, + { 89, 901, 3, { 180, 338, 504, 588}}, + { 93, 991, 3, { 196, 364, 546, 650}}, + { 97, 1085, 3, { 224, 416, 600, 700}}, //20 + {101, 1156, 4, { 224, 442, 644, 750}}, + {105, 1258, 4, { 252, 476, 690, 816}}, + {109, 1364, 4, { 270, 504, 750, 900}}, + {113, 1474, 4, { 300, 560, 810, 960}}, + {117, 1588, 4, { 312, 588, 870, 1050}}, //25 + {121, 1706, 4, { 336, 644, 952, 1110}}, + {125, 1828, 4, { 360, 700, 1020, 1200}}, + {129, 1921, 3, { 390, 728, 1050, 1260}}, + {133, 2051, 3, { 420, 784, 1140, 1350}}, + {137, 2185, 3, { 450, 812, 1200, 1440}}, //30 + {141, 2323, 3, { 480, 868, 1290, 1530}}, + {145, 2465, 3, { 510, 924, 1350, 1620}}, + {149, 2611, 3, { 540, 980, 1440, 1710}}, + {153, 2761, 3, { 570, 1036, 1530, 1800}}, + {157, 2876, 0, { 570, 1064, 1590, 1890}}, //35 + {161, 3034, 0, { 600, 1120, 1680, 1980}}, + {165, 3196, 0, { 630, 1204, 1770, 2100}}, + {169, 3362, 0, { 660, 1260, 1860, 2220}}, + {173, 3532, 0, { 720, 1316, 1950, 2310}}, + {177, 3706, 0, { 750, 1372, 2040, 2430}} //40 +}; + +int QRspec_getDataLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].words - qrspecCapacity[version].ec[level]; +} + +int QRspec_getECCLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].ec[level]; +} + +int QRspec_getMinimumVersion(int size, QRecLevel level) +{ + int i; + int words; + + for(i = 1; i <= QRSPEC_VERSION_MAX; i++) { + words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level]; + if(words >= size) return i; + } + + return QRSPEC_VERSION_MAX; +} + +int QRspec_getWidth(int version) +{ + return qrspecCapacity[version].width; +} + +int QRspec_getRemainder(int version) +{ + return qrspecCapacity[version].remainder; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +static const int lengthTableBits[4][3] = { + {10, 12, 14}, + { 9, 11, 13}, + { 8, 16, 16}, + { 8, 10, 12} +}; + +int QRspec_lengthIndicator(QRencodeMode mode, int version) +{ + int l; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + return lengthTableBits[mode][l]; +} + +int QRspec_maximumWords(QRencodeMode mode, int version) +{ + int l; + int bits; + int words; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + bits = lengthTableBits[mode][l]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Table of the error correction code (Reed-Solomon block) + * See Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = { + {{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}, + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1 + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, + {{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5 + {{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}}, + {{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}}, + {{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}}, + {{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}}, + {{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10 + {{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}}, + {{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}}, + {{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}}, + {{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}}, + {{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15 + {{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}}, + {{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}}, + {{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}}, + {{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}}, + {{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20 + {{ 4, 4}, {17, 0}, {17, 6}, {19, 6}}, + {{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}}, + {{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}}, + {{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}}, + {{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25 + {{10, 2}, {19, 4}, {28, 6}, {33, 4}}, + {{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}}, + {{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}}, + {{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}}, + {{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30 + {{13, 3}, { 2, 29}, {42, 1}, {23, 28}}, + {{17, 0}, {10, 23}, {10, 35}, {19, 35}}, + {{17, 1}, {14, 21}, {29, 19}, {11, 46}}, + {{13, 6}, {14, 23}, {44, 7}, {59, 1}}, + {{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35 + {{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}}, + {{17, 4}, {29, 14}, {49, 10}, {24, 46}}, + {{ 4, 18}, {13, 32}, {48, 14}, {42, 32}}, + {{20, 4}, {40, 7}, {43, 22}, {10, 67}}, + {{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40 +}; + +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]) +{ + int b1, b2; + int data, ecc; + + b1 = eccTable[version][level][0]; + b2 = eccTable[version][level][1]; + data = QRspec_getDataLength(version, level); + ecc = QRspec_getECCLength(version, level); + + if(b2 == 0) { + spec[0] = b1; + spec[1] = data / b1; + spec[2] = ecc / b1; + spec[3] = spec[4] = 0; + } else { + spec[0] = b1; + spec[1] = data / (b1 + b2); + spec[2] = ecc / (b1 + b2); + spec[3] = b2; + spec[4] = spec[1] + 1; + } +} + +/****************************************************************************** + * Alignment pattern + *****************************************************************************/ + +/** + * Positions of alignment patterns. + * This array includes only the second and the third position of the alignment + * patterns. Rest of them can be calculated from the distance between them. + * + * See Table 1 in Appendix E (pp.71) of JIS X0510:2004. + */ +static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = { + { 0, 0}, + { 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5 + {34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10 + {30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15 + {26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20 + {28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25 + {30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30 + {30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35 + {24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40 +}; + +/** + * Put an alignment marker. + * @param frame + * @param width + * @param ox,oy center coordinate of the pattern + */ +static void QRspec_putAlignmentMarker(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa1, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + }; + int x, y; + const unsigned char *s; + + frame += (oy - 2) * width + ox - 2; + s = finder; + for(y = 0; y < 5; y++) { + for(x = 0; x < 5; x++) { + frame[x] = s[x]; + } + frame += width; + s += 5; + } +} + +static void QRspec_putAlignmentPattern(int version, unsigned char *frame, int width) +{ + int d, w, x, y, cx, cy; + + if(version < 2) return; + + d = alignmentPattern[version][1] - alignmentPattern[version][0]; + if(d < 0) { + w = 2; + } else { + w = (width - alignmentPattern[version][0]) / d + 2; + } + + if(w * w - 3 == 1) { + x = alignmentPattern[version][0]; + y = alignmentPattern[version][0]; + QRspec_putAlignmentMarker(frame, width, x, y); + return; + } + + cx = alignmentPattern[version][0]; + for(x = 1; x < w - 1; x++) { + QRspec_putAlignmentMarker(frame, width, 6, cx); + QRspec_putAlignmentMarker(frame, width, cx, 6); + cx += d; + } + + cy = alignmentPattern[version][0]; + for(y = 0; y < w-1; y++) { + cx = alignmentPattern[version][0]; + for(x = 0; x < w-1; x++) { + QRspec_putAlignmentMarker(frame, width, cx, cy); + cx += d; + } + cy += d; + } +} + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Version information pattern (BCH coded). + * See Table 1 in Appendix D (pp.68) of JIS X0510:2004. + */ +static const unsigned int versionPattern[QRSPEC_VERSION_MAX - 6] = { + 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, + 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, + 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, + 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, + 0x27541, 0x28c69 +}; + +unsigned int QRspec_getVersionPattern(int version) +{ + if(version < 7 || version > QRSPEC_VERSION_MAX) return 0; + + return versionPattern[version - 7]; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_qrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976}, + {0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0}, + {0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed}, + {0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b} +}; + +unsigned int QRspec_getFormatInfo(int mask, QRecLevel level) +{ + if(mask < 0 || mask > 7) return 0; + + return formatInfo[level][mask]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Put a finder pattern. + * @param frame + * @param width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y = 0; y < 7; y++) { + for(x = 0; x < 7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + + +static unsigned char *QRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + unsigned int verinfo, v; + + width = qrspecCapacity[version].width; + frame = (unsigned char *)malloc((size_t)(width * width)); + if(frame == NULL) return NULL; + + memset(frame, 0, (size_t)(width * width)); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + putFinderPattern(frame, width, width - 7, 0); + putFinderPattern(frame, width, 0, width - 7); + /* Separator */ + p = frame; + q = frame + width * (width - 7); + for(y = 0; y < 7; y++) { + p[7] = 0xc0; + p[width - 8] = 0xc0; + q[7] = 0xc0; + p += width; + q += width; + } + memset(frame + width * 7, 0xc0, 8); + memset(frame + width * 8 - 8, 0xc0, 8); + memset(frame + width * (width - 8), 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8, 0x84, 9); + memset(frame + width * 9 - 8, 0x84, 8); + p = frame + 8; + for(y = 0; y < 8; y++) { + *p = 0x84; + p += width; + } + p = frame + width * (width - 7) + 8; + for(y = 0; y < 7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + width * 6 + 8; + q = frame + width * 8 + 6; + for(x = 1; x < width-15; x++) { + *p = 0x90 | (x & 1); + *q = 0x90 | (x & 1); + p++; + q += width; + } + /* Alignment pattern */ + QRspec_putAlignmentPattern(version, frame, width); + + /* Version information */ + if(version >= 7) { + verinfo = QRspec_getVersionPattern(version); + + p = frame + width * (width - 11); + v = verinfo; + for(x = 0; x < 6; x++) { + for(y = 0; y < 3; y++) { + p[width * y + x] = 0x88 | (v & 1); + v = v >> 1; + } + } + + p = frame + width - 11; + v = verinfo; + for(y = 0; y < 6; y++) { + for(x = 0; x < 3; x++) { + p[x] = 0x88 | (v & 1); + v = v >> 1; + } + p += width; + } + } + /* and a little bit... */ + frame[width * (width - 8) + 8] = 0x81; + + return frame; +} + +unsigned char *QRspec_newFrame(int version) +{ + if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL; + + return QRspec_createFrame(version); +} diff --git a/datafile/qrencode/qrspec.h b/datafile/qrencode/qrspec.h new file mode 100644 index 0000000..4d01879 --- /dev/null +++ b/datafile/qrencode/qrspec.h @@ -0,0 +1,174 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QRSPEC_H +#define QRSPEC_H + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define QRSPEC_WIDTH_MAX 177 + +/** + * Return maximum data code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return maximum size (bytes) + */ +extern int QRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version version of the symbol + * @param level error correction level + * @return ECC size (bytes) + */ +extern int QRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level error correction level + * @return version number + */ +extern int QRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version vesion of the symbol + * @return width of the symbol + */ +extern int QRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version vesion of the symbol + * @return number of remainder bits + */ +extern int QRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of length indicator for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the size of the appropriate length indicator (bits). + */ +extern int QRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode encode mode + * @param version vesion of the symbol + * @return the maximum length (bytes) + */ +extern int QRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Return an array of ECC specification. + * @param version version of the symbol + * @param level error correction level + * @param spec an array of ECC specification contains as following: + * {# of type1 blocks, # of data code, # of ecc code, + * # of type2 blocks, # of data code} + */ +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]); + +#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3]) +#define QRspec_rsBlockNum1(__spec__) (__spec__[0]) +#define QRspec_rsDataCodes1(__spec__) (__spec__[1]) +#define QRspec_rsEccCodes1(__spec__) (__spec__[2]) +#define QRspec_rsBlockNum2(__spec__) (__spec__[3]) +#define QRspec_rsDataCodes2(__spec__) (__spec__[4]) +#define QRspec_rsEccCodes2(__spec__) (__spec__[2]) + +#define QRspec_rsDataLength(__spec__) \ + ((QRspec_rsBlockNum1(__spec__) * QRspec_rsDataCodes1(__spec__)) + \ + (QRspec_rsBlockNum2(__spec__) * QRspec_rsDataCodes2(__spec__))) +#define QRspec_rsEccLength(__spec__) \ + (QRspec_rsBlockNum(__spec__) * QRspec_rsEccCodes1(__spec__)) + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version version of the symbol + * @return BCH encoded version information pattern + */ +extern unsigned int QRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask mask number + * @param level error correction level + * @return BCH encoded format information pattern + */ +extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * @param version version of the symbol + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *QRspec_newFrame(int version); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 of JIS X0510:2004, pp.16. + */ +#define QRSPEC_MODEID_ECI 7 +#define QRSPEC_MODEID_NUM 1 +#define QRSPEC_MODEID_AN 2 +#define QRSPEC_MODEID_8 4 +#define QRSPEC_MODEID_KANJI 8 +#define QRSPEC_MODEID_FNC1FIRST 5 +#define QRSPEC_MODEID_FNC1SECOND 9 +#define QRSPEC_MODEID_STRUCTURE 3 +#define QRSPEC_MODEID_TERMINATOR 0 + +#endif /* QRSPEC_H */ diff --git a/datafile/qrencode/rsecc.c b/datafile/qrencode/rsecc.c new file mode 100644 index 0000000..b88cae3 --- /dev/null +++ b/datafile/qrencode/rsecc.c @@ -0,0 +1,149 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon error correction code encoder specialized for QR code. + * This code is rewritten by Kentaro Fukuchi, referring to the FEC library + * developed by Phil Karn (KA9Q). + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * Copyright (C) 2014-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#if HAVE_LIBPTHREAD +#include +#endif + +#include "rsecc.h" + +#if HAVE_LIBPTHREAD +static pthread_mutex_t RSECC_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static int initialized = 0; + +#define SYMBOL_SIZE (8) +#define symbols ((1U << SYMBOL_SIZE) - 1) +static const unsigned int proot = 0x11d; /* stands for x^8+x^4+x^3+x^2+1 (see pp.37 of JIS X0510:2004) */ + +/* min/max codeword length of ECC, calculated from the specification. */ +#define min_length (2) +#define max_length (30) +#define max_generatorSize (max_length) + +static unsigned char alpha[symbols + 1]; +static unsigned char aindex[symbols + 1]; +static unsigned char generator[max_length - min_length + 1][max_generatorSize + 1]; +static unsigned char generatorInitialized[max_length - min_length + 1]; + +static void RSECC_initLookupTable(void) +{ + unsigned int i, b; + + alpha[symbols] = 0; + aindex[0] = symbols; + + b = 1; + for(i = 0; i < symbols; i++) { + alpha[i] = b; + aindex[b] = i; + b <<= 1; + if(b & (symbols + 1)) { + b ^= proot; + } + b &= symbols; + } +} + +static void RSECC_init(void) +{ + RSECC_initLookupTable(); + memset(generatorInitialized, 0, (max_length - min_length + 1)); + initialized = 1; +} + +static void generator_init(size_t length) +{ + size_t i, j; + int g[max_generatorSize + 1]; + + g[0] = 1; + for(i = 0; i < length; i++) { + g[i + 1] = 1; + /* Because g[0] never be zero, skipped some conditional checks. */ + for(j = i; j > 0; j--) { + g[j] = g[j - 1] ^ alpha[(aindex[g[j]] + i) % symbols]; + } + g[0] = alpha[(aindex[g[0]] + i) % symbols]; + } + + for(i = 0; i <= length; i++) { + generator[length - min_length][i] = aindex[g[i]]; + } + + generatorInitialized[length - min_length] = 1; +} + +int RSECC_encode(size_t data_length, size_t ecc_length, const unsigned char *data, unsigned char *ecc) +{ + size_t i, j; + unsigned char feedback; + unsigned char *gen; + +#if HAVE_LIBPTHREAD + pthread_mutex_lock(&RSECC_mutex); +#endif + if(!initialized) { + RSECC_init(); + } +#if HAVE_LIBPTHREAD + pthread_mutex_unlock(&RSECC_mutex); +#endif + + if(ecc_length > max_length) return -1; + + memset(ecc, 0, ecc_length); +#if HAVE_LIBPTHREAD + pthread_mutex_lock(&RSECC_mutex); +#endif + if(!generatorInitialized[ecc_length - min_length]) generator_init(ecc_length); +#if HAVE_LIBPTHREAD + pthread_mutex_unlock(&RSECC_mutex); +#endif + gen = generator[ecc_length - min_length]; + + for(i = 0; i < data_length; i++) { + feedback = aindex[data[i] ^ ecc[0]]; + if(feedback != symbols) { + for(j = 1; j < ecc_length; j++) { + ecc[j] ^= alpha[(unsigned int)(feedback + gen[ecc_length - j]) % symbols]; + } + } + memmove(&ecc[0], &ecc[1], ecc_length - 1); + if(feedback != symbols) { + ecc[ecc_length - 1] = alpha[(unsigned int)(feedback + gen[0]) % symbols]; + } else { + ecc[ecc_length - 1] = 0; + } + } + + return 0; +} diff --git a/datafile/qrencode/rsecc.h b/datafile/qrencode/rsecc.h new file mode 100644 index 0000000..2c17ded --- /dev/null +++ b/datafile/qrencode/rsecc.h @@ -0,0 +1,31 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon error correction code encoder specialized for QR code. + * This code is rewritten by Kentaro Fukuchi, referring to the FEC library + * developed by Phil Karn (KA9Q). + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * Copyright (C) 2014-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef RSECC_H +#define RSECC_H + +extern int RSECC_encode(size_t data_length, size_t ecc_length, const unsigned char *data, unsigned char *ecc); + +#endif /* RSECC_H */ diff --git a/datafile/qrencode/split.c b/datafile/qrencode/split.c new file mode 100644 index 0000000..a79bf03 --- /dev/null +++ b/datafile/qrencode/split.c @@ -0,0 +1,323 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include "qrencode.h" +#include "qrinput.h" +#include "qrspec.h" +#include "split.h" + +#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10) +#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0) + +#if !HAVE_STRDUP +#undef strdup +char *strdup(const char *s) +{ + size_t len = strlen(s) + 1; + void *newstring = malloc(len); + if(newstring == NULL) return NULL; + return (char *)memcpy(newstring, s, len); +} +#endif + +static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint) +{ + unsigned char c, d; + unsigned int word; + + c = (unsigned char)string[0]; + + if(c == '\0') return QR_MODE_NUL; + if(isdigit(c)) { + return QR_MODE_NUM; + } else if(isalnum(c)) { + return QR_MODE_AN; + } else if(hint == QR_MODE_KANJI) { + d = (unsigned char)string[1]; + if(d != '\0') { + word = ((unsigned int)c << 8) | d; + if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) { + return QR_MODE_KANJI; + } + } + } + + return QR_MODE_8; +} + +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint); +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint); + +static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint) +{ + const char *p; + int ret; + int run; + int dif; + int ln; + QRencodeMode mode; + + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isdigit(*p)) { + p++; + } + run = (int)(p - string); + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_8) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + if(mode == QR_MODE_AN) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsModeAn(1) /* + 4 + la */ + - QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */; + if(dif > 0) { + return Split_eatAn(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + int ret; + int run; + int dif; + int la, ln; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isalnum(*p)) { + if(isdigit(*p)) { + q = p; + while(isdigit(*q)) { + q++; + } + dif = QRinput_estimateBitsModeAn((int)(p - string)) /* + 4 + la */ + + QRinput_estimateBitsModeNum((int)(q - p)) + 4 + ln + + (isalnum(*q)?(4 + ln):0) + - QRinput_estimateBitsModeAn((int)(q - string)) /* - 4 - la */; + if(dif < 0) { + break; + } + p = q; + } else { + p++; + } + } + + run = (int)(p - string); + + if(*p && !isalnum(*p)) { + dif = QRinput_estimateBitsModeAn(run) + 4 + la + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p; + int ret; + int run; + + p = string; + while(Split_identifyMode(p, hint) == QR_MODE_KANJI) { + p += 2; + } + run = (int)(p - string); + ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + QRencodeMode mode; + int ret; + int run; + int dif; + int la, ln, l8; + int swcost; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + l8 = QRspec_lengthIndicator(QR_MODE_8, input->version); + + p = string + 1; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + break; + } + if(mode == QR_MODE_NUM) { + q = p; + while(isdigit(*q)) { + q++; + } + if(Split_identifyMode(q, hint) == QR_MODE_8) { + swcost = 4 + l8; + } else { + swcost = 0; + } + dif = QRinput_estimateBitsMode8((int)(p - string)) /* + 4 + l8 */ + + QRinput_estimateBitsModeNum((int)(q - p)) + 4 + ln + + swcost + - QRinput_estimateBitsMode8((int)(q - string)) /* - 4 - l8 */; + if(dif < 0) { + break; + } + p = q; + } else if(mode == QR_MODE_AN) { + q = p; + while(isalnum(*q)) { + q++; + } + if(Split_identifyMode(q, hint) == QR_MODE_8) { + swcost = 4 + l8; + } else { + swcost = 0; + } + dif = QRinput_estimateBitsMode8((int)(p - string)) /* + 4 + l8 */ + + QRinput_estimateBitsModeAn((int)(q - p)) + 4 + la + + swcost + - QRinput_estimateBitsMode8((int)(q - string)) /* - 4 - l8 */; + if(dif < 0) { + break; + } + p = q; + } else { + p++; + } + } + + run = (int)(p - string); + ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_splitString(const char *string, QRinput *input, + QRencodeMode hint) +{ + int length; + QRencodeMode mode; + + while(*string != '\0') { + mode = Split_identifyMode(string, hint); + if(mode == QR_MODE_NUM) { + length = Split_eatNum(string, input, hint); + } else if(mode == QR_MODE_AN) { + length = Split_eatAn(string, input, hint); + } else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) { + length = Split_eatKanji(string, input, hint); + } else { + length = Split_eat8(string, input, hint); + } + if(length == 0) break; + if(length < 0) return -1; + string += length; + } + + return 0; +} + +static char *dupAndToUpper(const char *str, QRencodeMode hint) +{ + char *newstr, *p; + QRencodeMode mode; + + newstr = strdup(str); + if(newstr == NULL) return NULL; + + p = newstr; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + p += 2; + } else { + if (*p >= 'a' && *p <= 'z') { + *p = (char)((int)*p - 32); + } + p++; + } + } + + return newstr; +} + +int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive) +{ + char *newstr; + int ret; + + if(string == NULL || *string == '\0') { + errno = EINVAL; + return -1; + } + if(!casesensitive) { + newstr = dupAndToUpper(string, hint); + if(newstr == NULL) return -1; + ret = Split_splitString(newstr, input, hint); + free(newstr); + } else { + ret = Split_splitString(string, input, hint); + } + + return ret; +} diff --git a/datafile/qrencode/split.h b/datafile/qrencode/split.h new file mode 100644 index 0000000..81829e0 --- /dev/null +++ b/datafile/qrencode/split.h @@ -0,0 +1,47 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SPLIT_H +#define SPLIT_H + +#include "qrencode.h" + +/** + * Split the input string (null terminated) into QRinput. + * @param string input string + * @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8. + * @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS. + * @retval 0 success. + * @retval -1 an error occurred. errno is set to indicate the error. See + * Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive); + +#endif /* SPLIT_H */ diff --git a/datafile/view/mygraphicsitem.cpp b/datafile/view/mygraphicsitem.cpp new file mode 100644 index 0000000..888fe8a --- /dev/null +++ b/datafile/view/mygraphicsitem.cpp @@ -0,0 +1,261 @@ +#include "mygraphicsitem.h" + +MyGraphicsItem::MyGraphicsItem() +{ + m_point.setX(0); + m_point.setY(0); + + //使item可以被选择 + //this->setFlag(QGraphicsItem::ItemIsSelectable); + //使item可以移动 + //this->setFlag(QGraphicsItem::ItemIsMovable); + //item可以响应鼠标事件 + //this->setAcceptHoverEvents(true); +} + +MyGraphicsItem::~MyGraphicsItem() +{ +} + +void MyGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + return QGraphicsItem::mousePressEvent(event); +} + +void MyGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + return QGraphicsItem::mouseMoveEvent(event); +} + +void MyGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + return QGraphicsItem::mouseReleaseEvent(event); +} + +QPicture MyGraphicsItem::getPicture(Marker marker,int penWidth) +{ + if(penWidth != 1) + { + QPicture pic; + CBitmapInfo bitmapInfo; + QPainterPath painterPath; + QRect rect = marker.GetRect(); + int minX = rect.left(); + int minY = rect.top(); + int maxY = rect.bottom(); + + int nLineCount = marker.m_listPolyline.size(); + for(int i = 0; i < nLineCount; i++) + { + CRPPolyline polyLine = marker.m_listPolyline.at(i); + int type = polyLine.m_nDrawingType; + + if(type == 0)//直线 + { + int nPointCount = polyLine.m_listPoint.size(); + for(int j = 0; j < nPointCount; j++) + { + double x = (polyLine.m_listPoint.at(j).x() - minX)/(double)M_IDPMM*MMPIXELY; + double y = ((0 - (polyLine.m_listPoint.at(j).y() - minY))+(maxY-minY))/(double)M_IDPMM*MMPIXELY; + QPointF point(x,y); + + if(j == 0) + { + painterPath.moveTo(point); + } + else + { + painterPath.lineTo(point); + } + } + } + else if(type == 1)//位图 + { + bitmapInfo = polyLine.m_bitmapInfo; + int x = bitmapInfo.m_ptAbPostLU.x(); + int y = bitmapInfo.m_ptAbPostLU.y(); + + int nx = (x - minX)/M_IDPMM*MMPIXELY; + int ny = ((0 - (y - minY))+(maxY-minY))/M_IDPMM*MMPIXELY; + + bitmapInfo.m_ptAbPostLU.setX(nx); + bitmapInfo.m_ptAbPostLU.setY(ny); + } + } + + if(painterPath.isEmpty()) + { + qDebug()<<"painterPath isEmpty"; + } + + //将路径画在picture上 + QPen pen; + pen.setWidth(penWidth);//设置笔号 + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPath(painterPath); + if(bitmapInfo.m_iBytes > 0)//有位图 + { + painter.drawPixmap(bitmapInfo.m_ptAbPostLU.x(),bitmapInfo.m_ptAbPostLU.y(),bitmapInfo.m_pBitmap); + } + painter.end(); + return pic; + } + return m_picture; +} + +void MyGraphicsItem::setPicture(QPicture pic) +{ + m_picture = pic; + // 外矩形 + m_boundingRect = m_picture.boundingRect(); + update(); +} + +void MyGraphicsItem::reflushBlockPos(QPoint p) +{ + m_point = p; + + m_blockPixmap = QPixmap(PIXMAPWIDTH,m_picture.height()); + m_blockPixmap.fill(Qt::transparent);//透明色 + if(m_point.x() >= 0 && m_point.y() >= 0) + { + QPainter painter(&m_blockPixmap); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(m_blockPixmap.rect(), QColor(0, 0, 0, 80)); + painter.end(); + } + update(); +} + +QRectF MyGraphicsItem::boundingRect() const +{ + return m_boundingRect; +} + +void MyGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + QPen pen; + QBrush brush; + brush.setStyle(Qt::SolidPattern); + pen.setWidth(1); + double scaleFactor = painter->matrix().m11(); + double width = pen.width()/scaleFactor; + pen.setWidthF(width); // 线段保持原来的线宽 + pen.setColor(QColor(Qt::black)); + brush.setColor(QColor(255,255,255)); + + painter->setPen(pen); + painter->setBrush(brush); + + //防锯齿,效果不好,所以注释掉 +// painter->setRenderHint(QPainter::Antialiasing, true); +// painter->setRenderHint(QPainter::SmoothPixmapTransform, true); + + painter->drawPicture(0,0,m_picture); + painter->drawPixmap(m_point.x(),m_point.y(),m_blockPixmap); +} + +void MyGraphicsItem::creatPicture(Marker marker) +{ + CBitmapInfo bitmapInfo; + QPainterPath painterPath; + QRect rect = marker.GetRect(); + int minX = rect.left(); + int minY = rect.top(); + int maxY = rect.bottom(); + + int nLineCount = marker.m_listPolyline.size(); + for(int i = 0; i < nLineCount; i++) + { + CRPPolyline polyLine = marker.m_listPolyline.at(i); + int type = polyLine.m_nDrawingType; + // if(polyLine.m_nDrawingType == 3)//文字 + // { + // CRPText text = polyLine.m_text; + // } + + if(type == 0)//直线 + { + int nPointCount = polyLine.m_listPoint.size(); + for(int j = 0; j < nPointCount; j++) + { + double x = (polyLine.m_listPoint.at(j).x() - minX)/(double)M_IDPMM*MMPIXELY; + double y = ((0 - (polyLine.m_listPoint.at(j).y() - minY))+(maxY-minY))/(double)M_IDPMM*MMPIXELY; + QPointF point(x,y); + + if(j == 0) + { + painterPath.moveTo(point); + } + else + { + painterPath.lineTo(point); + } + } + } + else if(type == 1)//位图 + { + bitmapInfo = polyLine.m_bitmapInfo; + int x = bitmapInfo.m_ptAbPostLU.x(); + int y = bitmapInfo.m_ptAbPostLU.y(); + + int nx = (x - minX)/M_IDPMM*MMPIXELY; + int ny = ((0 - (y - minY))+(maxY-minY))/M_IDPMM*MMPIXELY; + + bitmapInfo.m_ptAbPostLU.setX(nx); + bitmapInfo.m_ptAbPostLU.setY(ny); + } + } + + if(painterPath.isEmpty()) + { + qDebug()<<"painterPath.isEmpty"; + } + + //将路径画在picture上 + QPicture pic; + QPen pen; + pen.setWidth(1);//设置笔号 + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPath(painterPath); + if(bitmapInfo.m_iBytes > 0)//有位图 + { + //bitmapInfo.m_pBitmap.save("D:\\1.bmp"); + painter.drawPixmap(bitmapInfo.m_ptAbPostLU.x(),bitmapInfo.m_ptAbPostLU.y(),bitmapInfo.m_pBitmap); + } + painter.end(); + m_picture = pic; + + // 外矩形 + m_boundingRect = m_picture.boundingRect(); +} + +void MyGraphicsItem::creatPicture(QPixmap pixmap) +{ + //将图片画在picture上 + QPicture pic; + QPen pen; + pen.setWidth(1);//设置笔号 + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPixmap(0,0,pixmap); + painter.end(); + m_picture = pic; + + // 外矩形 + m_boundingRect = m_picture.boundingRect(); +} diff --git a/datafile/view/mygraphicsitem.h b/datafile/view/mygraphicsitem.h new file mode 100644 index 0000000..a86915e --- /dev/null +++ b/datafile/view/mygraphicsitem.h @@ -0,0 +1,54 @@ +#ifndef MYGRAPHICSITEM_H +#define MYGRAPHICSITEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "machine/bmp/creatprintbmp.h" +#include "datafile/hpgl/importhpgl.h" + +class MyGraphicsItem : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) //通知要实现的类构成何种界面的宏 + +public: + MyGraphicsItem(); + ~MyGraphicsItem(); + + //绘图区域 + QRectF boundingRect() const; + //绘制按钮图像的函数 + void paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, + QWidget *widget = 0); + + void creatPicture(Marker marker); + void creatPicture(QPixmap pixmap); + +protected: //事件 + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + +private: + QPicture m_picture; + QPixmap m_blockPixmap; + QPoint m_point; + QRectF m_boundingRect;//返回形状 + +public: + QPicture getPicture(Marker marker,int penWidth = 1); + void setPicture(QPicture pic); + void reflushBlockPos(QPoint p);//更显打印块位置 + +public slots: +}; + +#endif // MYGRAPHICSITEM_H diff --git a/datafile/view/mygraphicsscene.cpp b/datafile/view/mygraphicsscene.cpp new file mode 100644 index 0000000..e12bbf2 --- /dev/null +++ b/datafile/view/mygraphicsscene.cpp @@ -0,0 +1,85 @@ +#include "mygraphicsscene.h" + +MyGraphicsScene::MyGraphicsScene() +{ + m_myGraphicsItem= new MyGraphicsItem(); +} + +MyGraphicsScene::~MyGraphicsScene() +{ + if(m_myGraphicsItem != NULL) + { + delete m_myGraphicsItem; + m_myGraphicsItem = NULL; + } +} + +void MyGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + return QGraphicsScene::mousePressEvent(mouseEvent); +} + +void MyGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + return QGraphicsScene::mouseMoveEvent(mouseEvent); +} + +void MyGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) +{ + return QGraphicsScene::mouseReleaseEvent(mouseEvent); +} + +void MyGraphicsScene::createScene(Marker marker) +{ + m_myGraphicsItem->creatPicture(marker); + //绘制留边 + this->setSceneRect(0,0,m_myGraphicsItem->boundingRect().width()+DRAWMARGINS,m_myGraphicsItem->boundingRect().height()+DRAWMARGINS); + //如果scene未超过graphicsView的范围,图形就是居中显示的 + this->addItem(m_myGraphicsItem); + m_myGraphicsItem->moveBy(DRAWMARGINS/2.0,DRAWMARGINS/2.0);//item居中显示 +} + +void MyGraphicsScene::createScene(QPixmap pixmap) +{ + m_myGraphicsItem->creatPicture(pixmap); + //绘制留边 + this->setSceneRect(0,0,m_myGraphicsItem->boundingRect().width()+DRAWMARGINS,m_myGraphicsItem->boundingRect().height()+DRAWMARGINS); + //如果scene未超过graphicsView的范围,图形就是居中显示的 + this->addItem(m_myGraphicsItem); + m_myGraphicsItem->moveBy(DRAWMARGINS/2.0,DRAWMARGINS/2.0);//item居中显示 +} + +void MyGraphicsScene::cleanScene() +{ + if(m_myGraphicsItem != NULL) + { + this->removeItem(m_myGraphicsItem); + } +} + +QPicture MyGraphicsScene::getPicture(Marker marker,int penWidth) +{ + QPicture pic; + if(m_myGraphicsItem != NULL) + { + pic = m_myGraphicsItem->getPicture(marker,penWidth); + } + return pic; +} + +void MyGraphicsScene::swithScene(QPicture pic) +{ + if(m_myGraphicsItem != NULL) + { + m_myGraphicsItem->setPicture(pic); + this->addItem(m_myGraphicsItem); + } +} + +void MyGraphicsScene::ReflushBlockScene(QPoint p) +{ + if(m_myGraphicsItem != NULL) + { + m_myGraphicsItem->reflushBlockPos(p); + } +} diff --git a/datafile/view/mygraphicsscene.h b/datafile/view/mygraphicsscene.h new file mode 100644 index 0000000..17c37c8 --- /dev/null +++ b/datafile/view/mygraphicsscene.h @@ -0,0 +1,38 @@ +#ifndef MYGRAPHICSSCENE_H +#define MYGRAPHICSSCENE_H + +#include +#include +#include "datafile/view/mygraphicsitem.h" + +#define DRAWMARGINS 200.0 //item在场景中绘制时的边距(留边) + +class MyGraphicsScene: public QGraphicsScene +{ + Q_OBJECT +public: + MyGraphicsScene(); + ~MyGraphicsScene(); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent); + void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent); + +private: + MyGraphicsItem *m_myGraphicsItem; + +public: + void createScene(Marker marker); + void createScene(QPixmap pixmap); + void cleanScene(); + QPicture getPicture(Marker marker,int penWidth = 1); + void swithScene(QPicture pic); + void ReflushBlockScene(QPoint p); + +signals: + +public slots: +}; + +#endif // MYGRAPHICSSCENE_H diff --git a/datafile/view/mygraphicsview.cpp b/datafile/view/mygraphicsview.cpp new file mode 100644 index 0000000..07bb8be --- /dev/null +++ b/datafile/view/mygraphicsview.cpp @@ -0,0 +1,240 @@ +#include "mygraphicsview.h" + +MyGraphicsView::MyGraphicsView() +{ + m_viewSize = this->size(); + m_scene = new MyGraphicsScene(); + this->setScene(m_scene); + setMouseTracking(true); // 跟踪鼠标位置 + +// this->setRenderHint(QPainter::Antialiasing, true); +// this->setRenderHint(QPainter::SmoothPixmapTransform, true);//防锯齿 +} + +MyGraphicsView::~MyGraphicsView() +{ + if(m_scene != NULL) + { + delete m_scene; + m_scene = NULL; + } +} + +void MyGraphicsView::resizeEvent(QResizeEvent *event) +{ + if(event == NULL){}//为了去掉警告 + + if(m_scene != NULL && m_viewSize != this->size()) + { + QRectF rectItem = m_scene->itemsBoundingRect(); + this->setScene(m_scene); + this->fitInView(rectItem, Qt::KeepAspectRatio); + } + m_viewSize = this->size(); +} + +void MyGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) +{ + qreal scaleFactor = this->matrix().m11(); + if(scaleFactor >= 20){return;} + + if(event->button() == Qt::LeftButton && + event->type() == QEvent::MouseButtonDblClick) + { + setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + scale(2.0, 2.0); + } + + if(event->button() == Qt::RightButton && + event->type() == QEvent::MouseButtonDblClick) + { + QRectF rectItem = m_scene->itemsBoundingRect(); + this->fitInView(rectItem, Qt::KeepAspectRatio); + } +} + +void MyGraphicsView::mousePressEvent(QMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + setDragMode(QGraphicsView::RubberBandDrag); + m_leftBtnPressed = true; + m_startPoint = m_endPoint = event->pos(); + } + else + { + setDragMode(QGraphicsView::NoDrag); + } + + if(event->button() == Qt::RightButton) + { + m_startPoint = event->pos(); + m_rightBtnPressed = true; + } + + QGraphicsView::mousePressEvent(event); +} + +//恢复原状 +void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + m_leftBtnPressed = false; + + if(m_startPoint.x() == m_endPoint.x() || m_startPoint.y() == m_endPoint.y()) + { + return; + } + + double cx = (m_endPoint.x() + m_startPoint.x()) / 2.0; + double cy = (m_endPoint.y() + m_startPoint.y()) / 2.0; + // 获取当前鼠标相对于scene的位置; + QPointF scenePos = this->mapToScene(QPoint(cx,cy)); + + // 获取view的宽高; + qreal viewWidth = this->viewport()->width(); + qreal viewHeight = this->viewport()->height(); + + // 获取当前鼠标位置相当于view大小的横纵比例; + qreal hScale = cx / viewWidth; + qreal vScale = cy / viewHeight; + + this->scale(2.0, 2.0); + // 将scene坐标转换为放大缩小后的坐标; + QPointF viewPoint = this->matrix().map(scenePos); + // 通过滚动条控制view放大缩小后的展示scene的位置; + horizontalScrollBar()->setValue(int(viewPoint.x() - viewWidth * hScale)); + verticalScrollBar()->setValue(int(viewPoint.y() - viewHeight * vScale)); + } + + if(event->button() == Qt::RightButton) + { + m_rightBtnPressed = false; + } +} + +void MyGraphicsView::mouseMoveEvent(QMouseEvent *event) +{ + //QGraphicsView坐标 + QPoint viewPoint = event->pos(); + //QGraphicsScene坐标 + QPointF scenePoint = mapToScene(viewPoint); + double x = scenePoint.x() / MMPIXELY; + double y = abs(abs(scenePoint.y()) - m_scene->itemsBoundingRect().height()) / MMPIXELY; + scenePoint.setX(x); + scenePoint.setY(y); + setMouseTracking(true); + siMouseMove(scenePoint); + + if(m_leftBtnPressed) + { + m_endPoint = event->pos(); + } + + if(m_rightBtnPressed) + { + QPoint delta = m_startPoint - event->pos(); + int hValue = horizontalScrollBar()->value(); + int vValue = verticalScrollBar()->value(); + horizontalScrollBar()->setValue(delta.x() + hValue); + verticalScrollBar()->setValue(delta.y() + vValue); + m_startPoint = event->pos(); + } + + QGraphicsView::mouseMoveEvent(event); +} + +void MyGraphicsView::wheelEvent(QWheelEvent *event) +{ + // 获取当前鼠标相对于view的位置; + QPointF cursorPoint = event->pos(); + // 获取当前鼠标相对于scene的位置; + QPointF scenePos = this->mapToScene(QPoint(cursorPoint.x(), cursorPoint.y())); + + // 获取view的宽高; + qreal viewWidth = this->viewport()->width(); + qreal viewHeight = this->viewport()->height(); + + // 获取当前鼠标位置相当于view大小的横纵比例; + qreal hScale = cursorPoint.x() / viewWidth; + qreal vScale = cursorPoint.y() / viewHeight; + + int wheelDeltaValue = event->delta(); + // 向上滚动,放大; + if (wheelDeltaValue > 0) + { + this->scale(1.2, 1.2); + } + // 向下滚动,缩小; + else + { + this->scale(1.0 / 1.2, 1.0 / 1.2); + } + + // 将scene坐标转换为放大缩小后的坐标; + QPointF viewPoint = this->matrix().map(scenePos); + // 通过滚动条控制view放大缩小后的展示scene的位置; + horizontalScrollBar()->setValue(int(viewPoint.x() - viewWidth * hScale)); + verticalScrollBar()->setValue(int(viewPoint.y() - viewHeight * vScale)); +} + +QPicture MyGraphicsView::getPicture(Marker marker,int penWidth) +{ + QPicture pic; + if(m_scene != NULL) + { + pic = m_scene->getPicture(marker,penWidth); + } + return pic; +} + +void MyGraphicsView::creatView(Marker marker) +{ + if(m_scene != NULL) + { + m_scene->createScene(marker); + QRectF rectItem = m_scene->itemsBoundingRect(); + this->fitInView(rectItem, Qt::KeepAspectRatio); + } +} + +void MyGraphicsView::creatView(QPixmap pixmap) +{ + if(m_scene != NULL) + { + m_scene->createScene(pixmap); + QRectF rectItem = m_scene->itemsBoundingRect(); + this->fitInView(rectItem, Qt::KeepAspectRatio); + } +} + +void MyGraphicsView::cleanView() +{ + if(m_scene != NULL) + { + //这里delete掉再重新new是因为view显示完大图再显示小图,图形会不居中,未找到其他解决方法 + delete m_scene; + m_scene = NULL; + m_scene = new MyGraphicsScene(); + this->setScene(m_scene); + } +} + +void MyGraphicsView::swithView(QPicture pic) +{ + if(m_scene != NULL) + { + m_scene->swithScene(pic); + QRectF rectItem = m_scene->itemsBoundingRect(); + this->fitInView(rectItem, Qt::KeepAspectRatio); + } +} + +void MyGraphicsView::reflushBlockView(QPoint p) +{ + if(m_scene != NULL) + { + m_scene->ReflushBlockScene(p); + } +} diff --git a/datafile/view/mygraphicsview.h b/datafile/view/mygraphicsview.h new file mode 100644 index 0000000..375de9e --- /dev/null +++ b/datafile/view/mygraphicsview.h @@ -0,0 +1,50 @@ +#ifndef MYGRAPHICSVIEW_H +#define MYGRAPHICSVIEW_H + +#include +#include +#include +#include +#include +#include "datafile/view/mygraphicsscene.h" + +class MyGraphicsView : public QGraphicsView +{ + Q_OBJECT +public: + MyGraphicsView(); + ~MyGraphicsView(); + +private: + MyGraphicsScene *m_scene; + QSize m_viewSize; + + //鼠标起始点和结束点 + QPoint m_startPoint; + QPoint m_endPoint; + bool m_leftBtnPressed = false; + bool m_rightBtnPressed = false; + +protected: + void resizeEvent(QResizeEvent *event);//窗口大小发生变化的时候,该函数触发 + void mouseDoubleClickEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent *event); + +public: + QPicture getPicture(Marker marker,int penWidth = 1); + void creatView(Marker marker); + void creatView(QPixmap pixmap); + void cleanView(); + void swithView(QPicture pic); + void reflushBlockView(QPoint p); + +signals: + void siMouseMove(QPointF point); + +public slots: +}; + +#endif // MYGRAPHICSVIEW_H diff --git a/datafile/zip/unzip.cpp b/datafile/zip/unzip.cpp new file mode 100644 index 0000000..a331046 --- /dev/null +++ b/datafile/zip/unzip.cpp @@ -0,0 +1,4334 @@ +#ifdef ZIP_STD +#include +#include +#include +#include +#ifdef _MSC_VER +#include // microsoft puts it here +#else +#include +#endif +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) +#include +#define lumkdir(t) (mkdir(t)) +#else +#include +#define lumkdir(t) (mkdir(t,0755)) +#endif +#include +#include +#include "unzip.h" +// +typedef unsigned short WORD; +#define _tcslen strlen +#define _tcsicmp stricmp +#define _tcsncpy strncpy +#define _tcsstr strstr +#define INVALID_HANDLE_VALUE 0 +#ifndef _T +#define _T(s) s +#endif +#ifndef S_IWUSR +#define S_IWUSR 0000200 +#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif +// +#else +#include +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include +#include +#include "unzip.h" +#endif +// +#ifdef UNICODE +#define _tsprintf swprintf +#else +#define _tsprintf sprintf +#endif + + +// THIS FILE is almost entirely based upon code by Jean-loup Gailly +// and Mark Adler. It has been modified by Lucian Wischik. +// The modifications were: incorporate the bugfixes of 1.1.4, allow +// unzipping to/from handles/pipes/files/memory, encryption, unicode, +// a windowsish api, and putting everything into a single .cpp file. +// The original code may be found at http://www.gzip.org/zlib/ +// The original copyright text follows. +// +// +// +// zlib.h -- interface of the 'zlib' general purpose compression library +// version 1.1.3, July 9th, 1998 +// +// Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Jean-loup Gailly Mark Adler +// jloup@gzip.org madler@alumni.caltech.edu +// +// +// The data format used by the zlib library is described by RFCs (Request for +// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt +// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +// +// +// The 'zlib' compression library provides in-memory compression and +// decompression functions, including integrity checks of the uncompressed +// data. This version of the library supports only one compression method +// (deflation) but other algorithms will be added later and will have the same +// stream interface. +// +// Compression can be done in a single step if the buffers are large +// enough (for example if an input file is mmap'ed), or can be done by +// repeated calls of the compression function. In the latter case, the +// application must provide more input and/or consume the output +// (providing more output space) before each call. +// +// The library also supports reading and writing files in gzip (.gz) format +// with an interface similar to that of stdio. +// +// The library does not install any signal handler. The decoder checks +// the consistency of the compressed data, so the library should never +// crash even in case of corrupted input. +// +// for more info about .ZIP format, see ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip +// PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip + +#define ZIP_HANDLE 1 +#define ZIP_FILENAME 2 +#define ZIP_MEMORY 3 + + +#define zmalloc(len) malloc(len) + +#define zfree(p) free(p) + +typedef unsigned long lutime_t; // define it ourselves since we don't include time.h + +/* +void *zmalloc(unsigned int len) +{ char *buf = new char[len+32]; + for (int i=0; i<16; i++) + { buf[i]=i; + buf[len+31-i]=i; + } + *((unsigned int*)buf) = len; + char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); + OutputDebugString(c); + return buf+16; +} + +void zfree(void *buf) +{ char c[1000]; wsprintf(c,"free 0x%lx",buf); + OutputDebugString(c); + char *p = ((char*)buf)-16; + unsigned int len = *((unsigned int*)p); + bool blown=false; + for (int i=0; i<16; i++) + { char lo = p[i]; + char hi = p[len+31-i]; + if (hi!=i || (lo!=i && i>4)) blown=true; + } + if (blown) + { OutputDebugString("BLOWN!!!"); + } + delete[] p; +} +*/ + + +typedef struct tm_unz_s +{ unsigned int tm_sec; // seconds after the minute - [0,59] + unsigned int tm_min; // minutes after the hour - [0,59] + unsigned int tm_hour; // hours since midnight - [0,23] + unsigned int tm_mday; // day of the month - [1,31] + unsigned int tm_mon; // months since January - [0,11] + unsigned int tm_year; // years - [1980..2044] +} tm_unz; + + + +// ---------------------------------------------------------------------- +// some windows<->linux portability things +#ifdef ZIP_STD +DWORD GetFilePosU(HANDLE hfout) +{ struct stat st; fstat(fileno(hfout),&st); + if ((st.st_mode&S_IFREG)==0) return 0xFFFFFFFF; + return ftell(hfout); +} + +bool FileExists(const TCHAR *fn) +{ struct stat st; + int res=stat(fn,&st); + return (res==0); +} + +FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) +{ struct tm t; + t.tm_year = (WORD)(((dosdate>>9)&0x7f) + 1980 - 1900); + t.tm_isdst = -1; + t.tm_mon = (WORD)((dosdate>>5)&0xf - 1); + t.tm_mday = (WORD)(dosdate&0x1f); + t.tm_hour = (WORD)((dostime>>11)&0x1f); + t.tm_min = (WORD)((dostime>>5)&0x3f); + t.tm_sec = (WORD)((dostime&0x1f)*2); + time_t t2 = mktime(&t); + return t2; +} + +void LocalFileTimeToFileTime(FILETIME *lft, FILETIME *ft) +{ *ft = *lft; +} + +FILETIME timet2filetime(const lutime_t t) +{ return t; +} + +#else +// ---------------------------------------------------------------------- +DWORD GetFilePosU(HANDLE hfout) +{ return SetFilePointer(hfout,0,0,FILE_CURRENT); +} + +FILETIME timet2filetime(const lutime_t t) +{ LONGLONG i = Int32x32To64(t,10000000) + 116444736000000000LL; + FILETIME ft; + ft.dwLowDateTime = (DWORD) i; + ft.dwHighDateTime = (DWORD)(i >>32); + return ft; +} + +FILETIME dosdatetime2filetime(WORD dosdate,WORD dostime) +{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 + // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 + SYSTEMTIME st; + st.wYear = (WORD)(((dosdate>>9)&0x7f) + 1980); + st.wMonth = (WORD)((dosdate>>5)&0xf); + st.wDay = (WORD)(dosdate&0x1f); + st.wHour = (WORD)((dostime>>11)&0x1f); + st.wMinute = (WORD)((dostime>>5)&0x3f); + st.wSecond = (WORD)((dostime&0x1f)*2); + st.wMilliseconds = 0; + FILETIME ft; SystemTimeToFileTime(&st,&ft); + return ft; +} + +bool FileExists(const TCHAR *fn) +{ return (GetFileAttributes(fn)!=0xFFFFFFFF); +} +#endif +// ---------------------------------------------------------------------- + + + +// unz_global_info structure contain global data about the ZIPfile +typedef struct unz_global_info_s +{ unsigned long number_entry; // total number of entries in the central dir on this disk + unsigned long size_comment; // size of the global comment of the zipfile +} unz_global_info; + +// unz_file_info contain information about a file in the zipfile +typedef struct unz_file_info_s +{ unsigned long version; // version made by 2 bytes + unsigned long version_needed; // version needed to extract 2 bytes + unsigned long flag; // general purpose bit flag 2 bytes + unsigned long compression_method; // compression method 2 bytes + unsigned long dosDate; // last mod file date in Dos fmt 4 bytes + unsigned long crc; // crc-32 4 bytes + unsigned long compressed_size; // compressed size 4 bytes + unsigned long uncompressed_size; // uncompressed size 4 bytes + unsigned long size_filename; // filename length 2 bytes + unsigned long size_file_extra; // extra field length 2 bytes + unsigned long size_file_comment; // file comment length 2 bytes + unsigned long disk_num_start; // disk number start 2 bytes + unsigned long internal_fa; // internal file attributes 2 bytes + unsigned long external_fa; // external file attributes 4 bytes + tm_unz tmu_date; +} unz_file_info; + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) +#define UNZ_PASSWORD (-106) + + + + + + + +#define ZLIB_VERSION "1.1.3" + + +// Allowed flush values; see deflate() for details +#define Z_NO_FLUSH 0 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 + + +// compression levels +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) + +// compression strategy; see deflateInit2() for details +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 + +// Possible values of the data_type field +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 + +// The deflate compression method (the only one supported in this version) +#define Z_DEFLATED 8 + +// for initializing zalloc, zfree, opaque +#define Z_NULL 0 + +// case sensitivity when searching for filenames +#define CASE_SENSITIVE 1 +#define CASE_INSENSITIVE 2 + + +// Return codes for the compression/decompression functions. Negative +// values are errors, positive values are used for special but normal events. +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) + + + +// Basic data types +typedef unsigned char Byte; // 8 bits +typedef unsigned int uInt; // 16 bits or more +typedef unsigned long uLong; // 32 bits or more +typedef void *voidpf; +typedef void *voidp; +typedef long z_off_t; + + + + + + + + + + + + +typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); +typedef void (*free_func) (voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + Byte *next_in; // next input byte + uInt avail_in; // number of bytes available at next_in + uLong total_in; // total nb of input bytes read so far + + Byte *next_out; // next output byte should be put there + uInt avail_out; // remaining free space at next_out + uLong total_out; // total nb of bytes output so far + + char *msg; // last error message, NULL if no error + struct internal_state *state; // not visible by applications + + alloc_func zalloc; // used to allocate the internal state + free_func zfree; // used to free the internal state + voidpf opaque; // private data object passed to zalloc and zfree + + int data_type; // best guess about the data type: ascii or binary + uLong adler; // adler32 value of the uncompressed data + uLong reserved; // reserved for future use +} z_stream; + +typedef z_stream *z_streamp; + + +// The application must update next_in and avail_in when avail_in has +// dropped to zero. It must update next_out and avail_out when avail_out +// has dropped to zero. The application must initialize zalloc, zfree and +// opaque before calling the init function. All other fields are set by the +// compression library and must not be updated by the application. +// +// The opaque value provided by the application will be passed as the first +// parameter for calls of zalloc and zfree. This can be useful for custom +// memory management. The compression library attaches no meaning to the +// opaque value. +// +// zalloc must return Z_NULL if there is not enough memory for the object. +// If zlib is used in a multi-threaded application, zalloc and zfree must be +// thread safe. +// +// The fields total_in and total_out can be used for statistics or +// progress reports. After compression, total_in holds the total size of +// the uncompressed data and may be saved for use in the decompressor +// (particularly if the decompressor wants to decompress everything in +// a single step). +// + + +// basic functions + +const char *zlibVersion (); +// The application can compare zlibVersion and ZLIB_VERSION for consistency. +// If the first character differs, the library code actually used is +// not compatible with the zlib.h header file used by the application. +// This check is automatically made by inflateInit. + + + + + + +int inflate (z_streamp strm, int flush); +// +// inflate decompresses as much data as possible, and stops when the input +// buffer becomes empty or the output buffer becomes full. It may some +// introduce some output latency (reading input without producing any output) +// except when forced to flush. +// +// The detailed semantics are as follows. inflate performs one or both of the +// following actions: +// +// - Decompress more input starting at next_in and update next_in and avail_in +// accordingly. If not all input can be processed (because there is not +// enough room in the output buffer), next_in is updated and processing +// will resume at this point for the next call of inflate(). +// +// - Provide more output starting at next_out and update next_out and avail_out +// accordingly. inflate() provides as much output as possible, until there +// is no more input data or no more space in the output buffer (see below +// about the flush parameter). +// +// Before the call of inflate(), the application should ensure that at least +// one of the actions is possible, by providing more input and/or consuming +// more output, and updating the next_* and avail_* values accordingly. +// The application can consume the uncompressed output when it wants, for +// example when the output buffer is full (avail_out == 0), or after each +// call of inflate(). If inflate returns Z_OK and with zero avail_out, it +// must be called again after making room in the output buffer because there +// might be more output pending. +// +// If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much +// output as possible to the output buffer. The flushing behavior of inflate is +// not specified for values of the flush parameter other than Z_SYNC_FLUSH +// and Z_FINISH, but the current implementation actually flushes as much output +// as possible anyway. +// +// inflate() should normally be called until it returns Z_STREAM_END or an +// error. However if all decompression is to be performed in a single step +// (a single call of inflate), the parameter flush should be set to +// Z_FINISH. In this case all pending input is processed and all pending +// output is flushed; avail_out must be large enough to hold all the +// uncompressed data. (The size of the uncompressed data may have been saved +// by the compressor for this purpose.) The next operation on this stream must +// be inflateEnd to deallocate the decompression state. The use of Z_FINISH +// is never required, but can be used to inform inflate that a faster routine +// may be used for the single inflate() call. +// +// If a preset dictionary is needed at this point (see inflateSetDictionary +// below), inflate sets strm-adler to the adler32 checksum of the +// dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise +// it sets strm->adler to the adler32 checksum of all output produced +// so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or +// an error code as described below. At the end of the stream, inflate() +// checks that its computed adler32 checksum is equal to that saved by the +// compressor and returns Z_STREAM_END only if the checksum is correct. +// +// inflate() returns Z_OK if some progress has been made (more input processed +// or more output produced), Z_STREAM_END if the end of the compressed data has +// been reached and all uncompressed output has been produced, Z_NEED_DICT if a +// preset dictionary is needed at this point, Z_DATA_ERROR if the input data was +// corrupted (input stream not conforming to the zlib format or incorrect +// adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent +// (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not +// enough memory, Z_BUF_ERROR if no progress is possible or if there was not +// enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR +// case, the application may then call inflateSync to look for a good +// compression block. +// + + +int inflateEnd (z_streamp strm); +// +// All dynamically allocated data structures for this stream are freed. +// This function discards any unprocessed input and does not flush any +// pending output. +// +// inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state +// was inconsistent. In the error case, msg may be set but then points to a +// static string (which must not be deallocated). + + // Advanced functions + +// The following functions are needed only in some special applications. + + + + + +int inflateSetDictionary (z_streamp strm, + const Byte *dictionary, + uInt dictLength); +// +// Initializes the decompression dictionary from the given uncompressed byte +// sequence. This function must be called immediately after a call of inflate +// if this call returned Z_NEED_DICT. The dictionary chosen by the compressor +// can be determined from the Adler32 value returned by this call of +// inflate. The compressor and decompressor must use exactly the same +// dictionary. +// +// inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a +// parameter is invalid (such as NULL dictionary) or the stream state is +// inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the +// expected one (incorrect Adler32 value). inflateSetDictionary does not +// perform any decompression: this will be done by subsequent calls of +// inflate(). + + +int inflateSync (z_streamp strm); +// +// Skips invalid compressed data until a full flush point can be found, or until all +// available input is skipped. No output is provided. +// +// inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR +// if no more input was provided, Z_DATA_ERROR if no flush point has been found, +// or Z_STREAM_ERROR if the stream structure was inconsistent. In the success +// case, the application may save the current current value of total_in which +// indicates where valid compressed data was found. In the error case, the +// application may repeatedly call inflateSync, providing more input each time, +// until success or end of the input data. + + +int inflateReset (z_streamp strm); +// This function is equivalent to inflateEnd followed by inflateInit, +// but does not free and reallocate all the internal decompression state. +// The stream will keep attributes that may have been set by inflateInit2. +// +// inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source +// stream state was inconsistent (such as zalloc or state being NULL). +// + + + +// checksum functions +// These functions are not related to compression but are exported +// anyway because they might be useful in applications using the +// compression library. + +uLong adler32 (uLong adler, const Byte *buf, uInt len); +// Update a running Adler-32 checksum with the bytes buf[0..len-1] and +// return the updated checksum. If buf is NULL, this function returns +// the required initial value for the checksum. +// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed +// much faster. Usage example: +// +// uLong adler = adler32(0L, Z_NULL, 0); +// +// while (read_buffer(buffer, length) != EOF) { +// adler = adler32(adler, buffer, length); +// } +// if (adler != original_adler) error(); + +uLong ucrc32 (uLong crc, const Byte *buf, uInt len); +// Update a running crc with the bytes buf[0..len-1] and return the updated +// crc. If buf is NULL, this function returns the required initial value +// for the crc. Pre- and post-conditioning (one's complement) is performed +// within this function so it shouldn't be done by the application. +// Usage example: +// +// uLong crc = crc32(0L, Z_NULL, 0); +// +// while (read_buffer(buffer, length) != EOF) { +// crc = crc32(crc, buffer, length); +// } +// if (crc != original_crc) error(); + + + + +const char *zError (int err); +int inflateSyncPoint (z_streamp z); +const uLong *get_crc_table (void); + + + +typedef unsigned char uch; +typedef uch uchf; +typedef unsigned short ush; +typedef ush ushf; +typedef unsigned long ulg; + + + +const char * const z_errmsg[10] = { // indexed by 2-zlib_error +"need dictionary", // Z_NEED_DICT 2 +"stream end", // Z_STREAM_END 1 +"", // Z_OK 0 +"file error", // Z_ERRNO (-1) +"stream error", // Z_STREAM_ERROR (-2) +"data error", // Z_DATA_ERROR (-3) +"insufficient memory", // Z_MEM_ERROR (-4) +"buffer error", // Z_BUF_ERROR (-5) +"incompatible version",// Z_VERSION_ERROR (-6) +""}; + + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +// To be used only when the state is known to be valid + + // common constants + + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +// The three kinds of block type + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +// The minimum and maximum match lengths + +#define PRESET_DICT 0x20 // preset dictionary flag in zlib header + + // target dependencies + +#define OS_CODE 0x0b // Window 95 & Windows NT + + + + // functions + +#define zmemzero(dest, len) memset(dest, 0, len) + +// Diagnostic functions +#define LuAssert(cond,msg) +#define LuTrace(x) +#define LuTracev(x) +#define LuTracevv(x) +#define LuTracec(c,x) +#define LuTracecv(c,x) + + +typedef uLong (*check_func) (uLong check, const Byte *buf, uInt len); +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size); +void zcfree (voidpf opaque, voidpf ptr); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) + +//void ZFREE(z_streamp strm,voidpf addr) +//{ *((strm)->zfree))((strm)->opaque, addr); +//} + +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + + + +// Huffman code lookup table entry--this entry is four bytes for machines +// that have 16-bit pointers (e.g. PC's in the small or medium model). + + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; // number of extra bits or operation + Byte Bits; // number of bits in this code or subcode + } what; + uInt pad; // pad structure to a power of 2 (4 bytes for + } word; // 16-bit, 8 bytes for 32-bit int's) + uInt base; // literal, length base, distance base, or table offset +}; + +// Maximum size of dynamic tree. The maximum found in a long but non- +// exhaustive search was 1004 huft structures (850 for length/literals +// and 154 for distances, the latter actually the result of an +// exhaustive search). The actual maximum is not known, but the +// value below is more than safe. +#define MANY 1440 + +int inflate_trees_bits ( + uInt *, // 19 code lengths + uInt *, // bits tree desired/actual depth + inflate_huft * *, // bits tree result + inflate_huft *, // space for trees + z_streamp); // for messages + +int inflate_trees_dynamic ( + uInt, // number of literal/length codes + uInt, // number of distance codes + uInt *, // that many (total) code lengths + uInt *, // literal desired/actual bit depth + uInt *, // distance desired/actual bit depth + inflate_huft * *, // literal/length tree result + inflate_huft * *, // distance tree result + inflate_huft *, // space for trees + z_streamp); // for messages + +int inflate_trees_fixed ( + uInt *, // literal desired/actual bit depth + uInt *, // distance desired/actual bit depth + const inflate_huft * *, // literal/length tree result + const inflate_huft * *, // distance tree result + z_streamp); // for memory allocation + + + + + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +inflate_blocks_statef * inflate_blocks_new ( + z_streamp z, + check_func c, // check function + uInt w); // window size + +int inflate_blocks ( + inflate_blocks_statef *, + z_streamp , + int); // initial return code + +void inflate_blocks_reset ( + inflate_blocks_statef *, + z_streamp , + uLong *); // check value on output + +int inflate_blocks_free ( + inflate_blocks_statef *, + z_streamp); + +void inflate_set_dictionary ( + inflate_blocks_statef *s, + const Byte *d, // dictionary + uInt n); // dictionary length + +int inflate_blocks_sync_point ( + inflate_blocks_statef *s); + + + + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +inflate_codes_statef *inflate_codes_new ( + uInt, uInt, + const inflate_huft *, const inflate_huft *, + z_streamp ); + +int inflate_codes ( + inflate_blocks_statef *, + z_streamp , + int); + +void inflate_codes_free ( + inflate_codes_statef *, + z_streamp ); + + + + +typedef enum { + IBM_TYPE, // get type bits (3, including end bit) + IBM_LENS, // get lengths for stored + IBM_STORED, // processing stored block + IBM_TABLE, // get table lengths + IBM_BTREE, // get bit lengths tree for a dynamic block + IBM_DTREE, // get length, distance trees for a dynamic block + IBM_CODES, // processing fixed or dynamic block + IBM_DRY, // output remaining window bytes + IBM_DONE, // finished last block, done + IBM_BAD} // got a data error--stuck here +inflate_block_mode; + +// inflate blocks semi-private state +struct inflate_blocks_state { + + // mode + inflate_block_mode mode; // current inflate_block mode + + // mode dependent information + union { + uInt left; // if STORED, bytes left to copy + struct { + uInt table; // table lengths (14 bits) + uInt index; // index into blens (or border) + uInt *blens; // bit lengths of codes + uInt bb; // bit length tree depth + inflate_huft *tb; // bit length decoding tree + } trees; // if DTREE, decoding info for trees + struct { + inflate_codes_statef + *codes; + } decode; // if CODES, current state + } sub; // submode + uInt last; // true if this block is the last block + + // mode independent information + uInt bitk; // bits in bit buffer + uLong bitb; // bit buffer + inflate_huft *hufts; // single malloc for tree space + Byte *window; // sliding window + Byte *end; // one byte after sliding window + Byte *read; // window read pointer + Byte *write; // window write pointer + check_func checkfn; // check function + uLong check; // check on output + +}; + + +// defines for inflate input/output +// update pointers and return +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +// get bytes and bits +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +// output bytes +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;m;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +// load local pointers +#define LOAD {LOADIN LOADOUT} + +// masks for lower bits (size given to avoid silly warnings with Visual C++) +// And'ing with mask[n] masks the lower n bits +const uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +// copy as much as possible from the sliding window to the output area +int inflate_flush (inflate_blocks_statef *, z_streamp, int); + +int inflate_fast (uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp ); + + + +const uInt fixed_bl = 9; +const uInt fixed_bd = 5; +const inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +const inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + + + + + + + +// copy as much as possible from the sliding window to the output area +int inflate_flush(inflate_blocks_statef *s,z_streamp z,int r) +{ + uInt n; + Byte *p; + Byte *q; + + // local copies of source and destination pointers + p = z->next_out; + q = s->read; + + // compute number of bytes to copy as far as end of window + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z->avail_out -= n; + z->total_out += n; + + // update check information + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + // copy as far as end of window + if (n!=0) // check for n!=0 to avoid waking up CodeGuard + { memcpy(p, q, n); + p += n; + q += n; + } + + // see if more to copy at beginning of window + if (q == s->end) + { + // wrap pointers + q = s->window; + if (s->write == s->end) + s->write = s->window; + + // compute bytes to copy + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z->avail_out -= n; + z->total_out += n; + + // update check information + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + // copy + if (n!=0) {memcpy(p,q,n); p+=n; q+=n;} + } + + // update pointers + z->next_out = p; + s->read = q; + + // done + return r; +} + + + + + + +// simplify the use of the inflate_huft type with some defines +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing + START, // x: set up for LEN + LEN, // i: get length/literal/eob next + LENEXT, // i: getting length extra (have base) + DIST, // i: get distance next + DISTEXT, // i: getting distance extra + COPY, // o: copying bytes in window, waiting for space + LIT, // o: got literal, waiting for output space + WASH, // o: got eob, possibly still output waiting + END, // x: got eob and all data flushed + BADCODE} // x: got error +inflate_codes_mode; + +// inflate codes private state +struct inflate_codes_state { + + // mode + inflate_codes_mode mode; // current inflate_codes mode + + // mode dependent information + uInt len; + union { + struct { + const inflate_huft *tree; // pointer into tree + uInt need; // bits needed + } code; // if LEN or DIST, where in tree + uInt lit; // if LIT, literal + struct { + uInt get; // bits to get for extra + uInt dist; // distance back to copy from + } copy; // if EXT or COPY, where and how much + } sub; // submode + + // mode independent information + Byte lbits; // ltree bits decoded per branch + Byte dbits; // dtree bits decoder per branch + const inflate_huft *ltree; // literal/length/eob tree + const inflate_huft *dtree; // distance tree + +}; + + +inflate_codes_statef *inflate_codes_new( +uInt bl, uInt bd, +const inflate_huft *tl, +const inflate_huft *td, // need separate declaration for Borland C++ +z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + LuTracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; // temporary storage + const inflate_huft *t; // temporary pointer + uInt e; // extra bits or operation + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + Byte *f; // pointer to copy strings from + inflate_codes_statef *c = s->sub.decode.codes; // codes state + + // copy input/output information to locals (UPDATE macro restores) + LOAD + + // process input and output based on current state + for(;;) switch (c->mode) + { // waiting for "i:"=input, "o:"=output, "x:"=nothing + case START: // x: set up for LEN +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif // !SLOW + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: // i: get length/literal/eob next + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) // literal + { + c->sub.lit = t->base; + LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) // length + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) // next table + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) // end of block + { + LuTracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; // invalid code + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: // i: getting length extra (have base) + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + LuTracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: // i: get distance next + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) // distance + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) // next table + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; // invalid code + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: // i: getting distance extra + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + LuTracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - c->sub.copy.dist; + while (f < s->window) // modulo window size-"while" instead + f += s->end - s->window; // of "if" handles invalid distances + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: // o: got literal, waiting for output space + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: // o: got eob, possibly more output + if (k > 7) // return unused byte, if any + { + //Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; // can always return one + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: // x: got error + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(inflate_codes_statef *c,z_streamp z) +{ ZFREE(z, c); + LuTracev((stderr, "inflate: codes free\n")); +} + + + +// infblock.c -- interpret and process block types to last block +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +//struct inflate_codes_state {int dummy;}; // for buggy compilers + + + +// Table for deflate from PKZIP's appnote.txt. +const uInt border[] = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +// +// Notes beyond the 1.93a appnote.txt: +// +// 1. Distance pointers never point before the beginning of the output stream. +// 2. Distance pointers can point back across blocks, up to 32k away. +// 3. There is an implied maximum of 7 bits for the bit length table and +// 15 bits for the actual data. +// 4. If only one code exists, then it is encoded using one bit. (Zero +// would be more efficient, but perhaps a little confusing.) If two +// codes exist, they are coded using one bit each (0 and 1). +// 5. There is no way of sending zero distance codes--a dummy must be +// sent if there are none. (History: a pre 2.0 version of PKZIP would +// store blocks with no distance codes, but this was discovered to be +// too harsh a criterion.) Valid only for 1.93a. 2.04c does allow +// zero distance codes, which is sent as one code of zero bits in +// length. +// 6. There are up to 286 literal/length codes. Code 256 represents the +// end-of-block. Note however that the static length tree defines +// 288 codes just to fill out the Huffman codes. Codes 286 and 287 +// cannot be used though, since there is no length base or extra bits +// defined for them. Similarily, there are up to 30 distance codes. +// However, static trees define 32 codes (all 5 bits) to fill out the +// Huffman codes, but the last two had better not show up in the data. +// 7. Unzip can check dynamic Huffman blocks for complete code sets. +// The exception is that a single code would not be complete (see #4). +// 8. The five bits following the block type is really the number of +// literal codes sent minus 257. +// 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits +// (1+6+6). Therefore, to output three times the length, you output +// three codes (1+1+1), whereas to output four times the same length, +// you only need two codes (1+3). Hmm. +//10. In the tree reconstruction algorithm, Code = Code + Increment +// only if BitLength(i) is not zero. (Pretty obvious.) +//11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) +//12. Note: length code 284 can represent 227-258, but length code 285 +// really is 258. The last length deserves its own, short code +// since it gets used a lot in very redundant files. The length +// 258 is special since 258 - 3 (the min match length) is 255. +//13. The literal/length and distance code bit lengths are read as a +// single stream of lengths. It is possible (and advantageous) for +// a repeat code (16, 17, or 18) to go across the boundary between +// the two sets of lengths. + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == IBM_CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = IBM_TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + LuTracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = IBM_TYPE; + LuTracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; // temporary storage + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + LOAD + + // process input based on current state + for(;;) switch (s->mode) + { + case IBM_TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: // stored + LuTracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; // go to byte boundary + DUMPBITS(t) + s->mode = IBM_LENS; // get length of stored block + break; + case 1: // fixed + LuTracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + const inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = IBM_CODES; + break; + case 2: // dynamic + LuTracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = IBM_TABLE; + break; + case 3: // illegal + DUMPBITS(3) + s->mode = IBM_BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case IBM_LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = IBM_BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; // dump bits + LuTracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); + break; + case IBM_STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + memcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + LuTracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? IBM_DRY : IBM_TYPE; + break; + case IBM_TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; + // remove this section to workaround bug in pkzip + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = IBM_BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } + // end remove + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + LuTracev((stderr, "inflate: table sizes ok\n")); + s->mode = IBM_BTREE; + case IBM_BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + r = t; + if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = IBM_BAD; + } + LEAVE + } + s->sub.trees.index = 0; + LuTracev((stderr, "inflate: bits tree ok\n")); + s->mode = IBM_DTREE; + case IBM_DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else // c == 16..18 + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = IBM_BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; // must be <= 9 for lookahead assumptions + bd = 6; // must be <= 9 for lookahead assumptions + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); + s->mode = IBM_BAD; + } + r = t; + LEAVE + } + LuTracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + ZFREE(z, s->sub.trees.blens); + s->mode = IBM_CODES; + case IBM_CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + LuTracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = IBM_TYPE; + break; + } + s->mode = IBM_DRY; + case IBM_DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = IBM_DONE; + case IBM_DONE: + r = Z_STREAM_END; + LEAVE + case IBM_BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + LuTracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + + +// inftrees.c -- generate Huffman trees for efficient decoding +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h +// + + + +extern const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +// If you use the zlib library in a product, an acknowledgment is welcome +// in the documentation of your product. If for some reason you cannot +// include such an acknowledgment, I would appreciate that you keep this +// copyright string in the executable of your product. + + + +int huft_build ( + uInt *, // code lengths in bits + uInt, // number of codes + uInt, // number of "simple" codes + const uInt *, // list of base values for non-simple codes + const uInt *, // list of extra bits for non-simple codes + inflate_huft **,// result: starting table + uInt *, // maximum lookup bits (returns actual) + inflate_huft *, // space for trees + uInt *, // hufts used in space + uInt * ); // space for values + +// Tables for deflate from PKZIP's appnote.txt. +const uInt cplens[31] = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + // see note #13 above about 258 +const uInt cplext[31] = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid +const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +const uInt cpdext[30] = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +// +// Huffman code decoding is performed using a multi-level table lookup. +// The fastest way to decode is to simply build a lookup table whose +// size is determined by the longest code. However, the time it takes +// to build this table can also be a factor if the data being decoded +// is not very long. The most common codes are necessarily the +// shortest codes, so those codes dominate the decoding time, and hence +// the speed. The idea is you can have a shorter table that decodes the +// shorter, more probable codes, and then point to subsidiary tables for +// the longer codes. The time it costs to decode the longer codes is +// then traded against the time it takes to make longer tables. +// +// This results of this trade are in the variables lbits and dbits +// below. lbits is the number of bits the first level table for literal/ +// length codes can decode in one step, and dbits is the same thing for +// the distance codes. Subsequent tables are also less than or equal to +// those sizes. These values may be adjusted either when all of the +// codes are shorter than that, in which case the longest code length in +// bits is used, or when the shortest code is *longer* than the requested +// table size, in which case the length of the shortest code in bits is +// used. +// +// There are two different values for the two tables, since they code a +// different number of possibilities each. The literal/length table +// codes 286 possible values, or in a flat code, a little over eight +// bits. The distance table codes 30 possible values, or a little less +// than five bits, flat. The optimum values for speed end up being +// about one bit more than those, so lbits is 8+1 and dbits is 5+1. +// The optimum values may differ though from machine to machine, and +// possibly even between compilers. Your mileage may vary. +// + + +// If BMAX needs to be larger than 16, then h and x[] should be uLong. +#define BMAX 15 // maximum bit length of any code + +int huft_build( +uInt *b, // code lengths in bits (all assumed <= BMAX) +uInt n, // number of codes (assumed <= 288) +uInt s, // number of simple-valued codes (0..s-1) +const uInt *d, // list of base values for non-simple codes +const uInt *e, // list of extra bits for non-simple codes +inflate_huft * *t, // result: starting table +uInt *m, // maximum lookup bits, returns actual +inflate_huft *hp, // space for trees +uInt *hn, // hufts used in space +uInt *v) // working area: values in order of bit length +// Given a list of code lengths and a maximum table size, make a set of +// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR +// if the given code set is incomplete (the tables are still built in this +// case), or Z_DATA_ERROR if the input is invalid. +{ + + uInt a; // counter for codes of length k + uInt c[BMAX+1]; // bit length count table + uInt f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + register uInt i; // counter, current code + register uInt j; // counter + register int k; // number of bits in current code + int l; // bits per table (returned in m) + uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP + register uInt *p; // pointer into c[], b[], or v[] + inflate_huft *q; // points to current table + struct inflate_huft_s r; // table entry for structure assignment + inflate_huft *u[BMAX]; // table stack + register int w; // bits before this table == (l * h) + uInt x[BMAX+1]; // bit offsets, then code stack + uInt *xp; // pointer into x + int y; // number of dummy codes added + uInt z; // number of entries in current table + + + // Generate counts for each bit length + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4; p; // clear c[]--assume BMAX+1 is 16 + p = b; i = n; + do { + c[*p++]++; // assume all entries <= BMAX + } while (--i); + if (c[0] == n) // null input--all zero length codes + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + // Find minimum and maximum length, bound *m by those + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; // minimum code length + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; // maximum code length + if ((uInt)l > i) + l = i; + *m = l; + + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { // note that i == g from above + *xp++ = (j += *p++); + } + + + // Make a table of values in order of bit lengths + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; // set n to length of v + + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = v; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy + q = (inflate_huft *)Z_NULL; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l) + { + h++; + w += l; // previous table always l bits + + // compute minimum size table less than or equal to l bits + z = g - w; + z = z > (uInt)l ? l : z; // table size upper limit + if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table + { // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = c + k; + if (j < z) + while (++j < z) // try smaller tables up to z bits + { + if ((f <<= 1) <= *++xp) + break; // enough codes to use up j bits + f -= *xp; // else deduct codes from patterns + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (*hn + z > MANY) // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + u[h] = q = hp + *hn; + *hn += z; + + // connect to last table, if there is one + if (h) + { + x[h] = i; // save pattern for backing up + r.bits = (Byte)l; // bits to dump before this table + r.exop = (Byte)j; // bits in this table + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); // offset to this table + u[h-1][j] = r; // connect to last table + } + else + *t = q; // first table is returned result + } + + // set up table entry in r + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; // out of values--invalid code + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block + r.base = *p++; // simple code is just the value + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);// non-simple--look up in lists + r.base = d[*p++ - s]; + } + + // fill code-like entries with r + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + // backwards increment the k-bit code i + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]) + { + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + + + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits( +uInt *c, // 19 code lengths +uInt *bb, // bits tree desired/actual depth +inflate_huft * *tb, // bits tree result +inflate_huft *hp, // space for trees +z_streamp z) // for messages +{ + int r; + uInt hn = 0; // hufts used in space + uInt *v; // work area for huft_build + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic( +uInt nl, // number of literal/length codes +uInt nd, // number of distance codes +uInt *c, // that many (total) code lengths +uInt *bl, // literal desired/actual bit depth +uInt *bd, // distance desired/actual bit depth +inflate_huft * *tl, // literal/length tree result +inflate_huft * *td, // distance tree result +inflate_huft *hp, // space for trees +z_streamp z) // for messages +{ + int r; + uInt hn = 0; // hufts used in space + uInt *v; // work area for huft_build + + // allocate work area + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + // build literal/length tree + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + // build distance tree + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + // done + ZFREE(z, v); + return Z_OK; +} + + + + + +int inflate_trees_fixed( +uInt *bl, // literal desired/actual bit depth +uInt *bd, // distance desired/actual bit depth +const inflate_huft * * tl, // literal/length tree result +const inflate_huft * *td, // distance tree result +z_streamp ) // for memory allocation +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +// inffast.c -- process literals and length/distance pairs fast +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h +// + + +//struct inflate_codes_state {int dummy;}; // for buggy compilers + + +// macros for bit input with no checking and for returning unused bytes +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +// Called with number of bytes left to write in window at least 258 +// (the maximum string length) and number of input bytes available +// at least ten. The ten bytes are six bytes for the longest length/ +// distance pair plus four bytes for overloading the bit buffer. + +int inflate_fast( +uInt bl, uInt bd, +const inflate_huft *tl, +const inflate_huft *td, // need separate declaration for Borland C++ +inflate_blocks_statef *s, +z_streamp z) +{ + const inflate_huft *t; // temporary pointer + uInt e; // extra bits or operation + uLong b; // bit buffer + uInt k; // bits in bit buffer + Byte *p; // input data pointer + uInt n; // bytes available there + Byte *q; // output window write pointer + uInt m; // bytes to end of window or read pointer + uInt ml; // mask for literal/length tree + uInt md; // mask for distance tree + uInt c; // bytes to copy + uInt d; // distance back to copy from + Byte *r; // copy source pointer + + // load input, output, bit values + LOAD + + // initialize masks + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + // do until not enough input or output space for fast loop + do { // assume called with m >= 258 && n >= 10 + // get literal/length code + GRABBITS(20) // max bits for literal/length code + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + for (;;) { + DUMPBITS(t->bits) + if (e & 16) + { + // get extra bits for length + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + LuTracevv((stderr, "inflate: * length %u\n", c)); + + // decode distance base of block to copy + GRABBITS(15); // max bits for distance code + e = (t = td + ((uInt)b & md))->exop; + for (;;) { + DUMPBITS(t->bits) + if (e & 16) + { + // get extra bits to add to distance base + e &= 15; + GRABBITS(e) // get extra bits (up to 13) + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + LuTracevv((stderr, "inflate: * distance %u\n", d)); + + // do the copy + m -= c; + r = q - d; + if (r < s->window) // wrap if needed + { + do { + r += s->end - s->window; // force pointer in window + } while (r < s->window); // covers invalid distances + e = (uInt) (s->end - r); + if (c > e) + { + c -= e; // wrapped copy + do { + *q++ = *r++; + } while (--e); + r = s->window; + do { + *q++ = *r++; + } while (--c); + } + else // normal copy + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + }; + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + LuTracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + }; + } while (m >= 258 && n >= 10); + + // not enough input or output--restore pointers and return + UNGRAB + UPDATE + return Z_OK; +} + + + + + + +// crc32.c -- compute the CRC-32 of a data stream +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +// @(#) $Id$ + + + + + + +// Table of CRC-32's of all single-byte values (made by make_crc_table) +const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +const uLong * get_crc_table() +{ return (const uLong *)crc_table; +} + +#define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define CRC_DO2(buf) CRC_DO1(buf); CRC_DO1(buf); +#define CRC_DO4(buf) CRC_DO2(buf); CRC_DO2(buf); +#define CRC_DO8(buf) CRC_DO4(buf); CRC_DO4(buf); + +uLong ucrc32(uLong crc, const Byte *buf, uInt len) +{ if (buf == Z_NULL) return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) {CRC_DO8(buf); len -= 8;} + if (len) do {CRC_DO1(buf);} while (--len); + return crc ^ 0xffffffffL; +} + + + +// ============================================================= +// some decryption routines +#define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8)) +void Uupdate_keys(unsigned long *keys, char c) +{ keys[0] = CRC32(keys[0],c); + keys[1] += keys[0] & 0xFF; + keys[1] = keys[1]*134775813L +1; + keys[2] = CRC32(keys[2], keys[1] >> 24); +} +char Udecrypt_byte(unsigned long *keys) +{ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; + return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); +} +char zdecode(unsigned long *keys, char c) +{ c^=Udecrypt_byte(keys); + Uupdate_keys(keys,c); + return c; +} + + + +// adler32.c -- compute the Adler-32 checksum of a data stream +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +// @(#) $Id$ + + +#define BASE 65521L // largest prime smaller than 65536 +#define NMAX 5552 +// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + +#define AD_DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define AD_DO2(buf,i) AD_DO1(buf,i); AD_DO1(buf,i+1); +#define AD_DO4(buf,i) AD_DO2(buf,i); AD_DO2(buf,i+2); +#define AD_DO8(buf,i) AD_DO4(buf,i); AD_DO4(buf,i+4); +#define AD_DO16(buf) AD_DO8(buf,0); AD_DO8(buf,8); + +// ========================================================================= +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + AD_DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + + + +// zutil.c -- target dependent utility functions for the compression library +// Copyright (C) 1995-1998 Jean-loup Gailly. +// For conditions of distribution and use, see copyright notice in zlib.h +// @(#) $Id$ + + + + + + +const char * zlibVersion() +{ + return ZLIB_VERSION; +} + +// exported to allow conversion of error code to string for compress() and +// uncompress() +const char * zError(int err) +{ return ERR_MSG(err); +} + + + + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; // make compiler happy + return (voidpf)calloc(items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + zfree(ptr); + if (opaque) return; // make compiler happy +} + + + +// inflate.c -- zlib interface to inflate modules +// Copyright (C) 1995-1998 Mark Adler +// For conditions of distribution and use, see copyright notice in zlib.h + +//struct inflate_blocks_state {int dummy;}; // for buggy compilers + +typedef enum { + IM_METHOD, // waiting for method byte + IM_FLAG, // waiting for flag byte + IM_DICT4, // four dictionary check bytes to go + IM_DICT3, // three dictionary check bytes to go + IM_DICT2, // two dictionary check bytes to go + IM_DICT1, // one dictionary check byte to go + IM_DICT0, // waiting for inflateSetDictionary + IM_BLOCKS, // decompressing blocks + IM_CHECK4, // four check bytes to go + IM_CHECK3, // three check bytes to go + IM_CHECK2, // two check bytes to go + IM_CHECK1, // one check byte to go + IM_DONE, // finished check, done + IM_BAD} // got an error--stay here +inflate_mode; + +// inflate private state +struct internal_state { + + // mode + inflate_mode mode; // current inflate mode + + // mode dependent information + union { + uInt method; // if IM_FLAGS, method byte + struct { + uLong was; // computed check value + uLong need; // stream check value + } check; // if CHECK, check values to compare + uInt marker; // if IM_BAD, inflateSync's marker bytes count + } sub; // submode + + // mode independent information + int nowrap; // flag for no wrapper + uInt wbits; // log2(window size) (8..15, defaults to 15) + inflate_blocks_statef + *blocks; // current inflate_blocks state + +}; + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + LuTracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + LuTracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int inflateInit2(z_streamp z) +{ const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; + + int w = -15; // MAX_WBITS: 32K LZ77 window. + // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files created by gzip. + // The memory requirements for deflate are (in bytes): + // (1 << (windowBits+2)) + (1 << (memLevel+9)) + // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + // plus a few kilobytes for small objects. For example, if you want to reduce + // the default memory requirements from 256K to 128K, compile with + // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + // Of course this will generally degrade compression (there's no free lunch). + // + // The memory requirements for inflate are (in bytes) 1 << windowBits + // that is, 32K for windowBits=15 (default value) plus a few kilobytes + // for small objects. + + // initialize state + if (z == Z_NULL) return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + // handle undocumented nowrap option (no zlib header or check) + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + // set window size + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + // create inflate_blocks state + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + LuTracev((stderr, "inflate: allocated\n")); + + // reset state + inflateReset(z); + return Z_OK; +} + + + +#define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + for (;;) switch (z->state->mode) + { + case IM_METHOD: + IM_NEEDBYTE + if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = IM_BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = IM_BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + z->state->mode = IM_FLAG; + case IM_FLAG: + IM_NEEDBYTE + b = IM_NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = IM_BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + LuTracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = IM_BLOCKS; + break; + } + z->state->mode = IM_DICT4; + case IM_DICT4: + IM_NEEDBYTE + z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; + z->state->mode = IM_DICT3; + case IM_DICT3: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; + z->state->mode = IM_DICT2; + case IM_DICT2: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; + z->state->mode = IM_DICT1; + case IM_DICT1: + IM_NEEDBYTE; r; + z->state->sub.check.need += (uLong)IM_NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = IM_DICT0; + return Z_NEED_DICT; + case IM_DICT0: + z->state->mode = IM_BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case IM_BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = IM_BAD; + z->state->sub.marker = 0; // can try inflateSync + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = IM_DONE; + break; + } + z->state->mode = IM_CHECK4; + case IM_CHECK4: + IM_NEEDBYTE + z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; + z->state->mode = IM_CHECK3; + case IM_CHECK3: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; + z->state->mode = IM_CHECK2; + case IM_CHECK2: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; + z->state->mode = IM_CHECK1; + case IM_CHECK1: + IM_NEEDBYTE + z->state->sub.check.need += (uLong)IM_NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = IM_BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; // can't try inflateSync + break; + } + LuTracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = IM_DONE; + case IM_DONE: + return Z_STREAM_END; + case IM_BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +} + + + + + +// unzip.c -- IO on .zip files using zlib +// Version 0.15 beta, Mar 19th, 1998, +// Read unzip.h for more info + + + + +#define UNZ_BUFSIZE (16384) +#define UNZ_MAXFILENAMEINZIP (256) +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = " unzip 0.15 Copyright 1998 Gilles Vollant "; + +// unz_file_info_interntal contain internal info about a file in zipfile +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;// relative offset of local header 4 bytes +} unz_file_info_internal; + + +typedef struct +{ bool is_handle; // either a handle or memory + bool canseek; + // for handles: + HANDLE h; bool herr; unsigned long initial_offset; bool mustclosehandle; + // for memory: + void *buf; unsigned int len,pos; // if it's a memory block +} LUFILE; + + +LUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err) +{ if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) {*err=ZR_ARGS; return NULL;} + // + HANDLE h=0; bool canseek=false; *err=ZR_OK; + bool mustclosehandle=false; + if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) + { if (flags==ZIP_HANDLE) + { HANDLE hf = (HANDLE)z; + h=hf; mustclosehandle=false; +#ifdef DuplicateHandle + BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS); + if (!res) mustclosehandle=true; +#endif + } + else + { +#ifdef ZIP_STD + h=fopen((const char*)z,"rb"); + if (h==0) {*err=ZR_NOFILE; return NULL;} +#else + h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if (h==INVALID_HANDLE_VALUE) {*err=ZR_NOFILE; return NULL;} +#endif + mustclosehandle=true; + } + // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. + DWORD res = GetFilePosU(h); + canseek = (res!=0xFFFFFFFF); + } + LUFILE *lf = new LUFILE; + if (flags==ZIP_HANDLE||flags==ZIP_FILENAME) + { lf->is_handle=true; lf->mustclosehandle=mustclosehandle; + lf->canseek=canseek; + lf->h=h; lf->herr=false; + lf->initial_offset=0; + if (canseek) lf->initial_offset = GetFilePosU(h); + } + else + { lf->is_handle=false; + lf->canseek=true; + lf->mustclosehandle=false; + lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0; + } + *err=ZR_OK; + return lf; +} + + +int lufclose(LUFILE *stream) +{ if (stream==NULL) return EOF; +#ifdef ZIP_STD + if (stream->mustclosehandle) fclose(stream->h); +#else + if (stream->mustclosehandle) CloseHandle(stream->h); +#endif + delete stream; + return 0; +} + +int luferror(LUFILE *stream) +{ if (stream->is_handle && stream->herr) return 1; + else return 0; +} + +long int luftell(LUFILE *stream) +{ if (stream->is_handle && stream->canseek) return GetFilePosU(stream->h)-stream->initial_offset; + else if (stream->is_handle) return 0; + else return stream->pos; +} + +int lufseek(LUFILE *stream, long offset, int whence) +{ if (stream->is_handle && stream->canseek) + { +#ifdef ZIP_STD + return fseek(stream->h,stream->initial_offset+offset,whence); +#else + if (whence==SEEK_SET) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN); + else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT); + else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END); + else return 19; // EINVAL + return 0; +#endif + } + else if (stream->is_handle) return 29; // ESPIPE + else + { if (whence==SEEK_SET) stream->pos=offset; + else if (whence==SEEK_CUR) stream->pos+=offset; + else if (whence==SEEK_END) stream->pos=stream->len+offset; + return 0; + } +} + + +size_t lufread(void *ptr,size_t size,size_t n,LUFILE *stream) +{ unsigned int toread = (unsigned int)(size*n); + if (stream->is_handle) + { +#ifdef ZIP_STD + return fread(ptr,size,n,stream->h); +#else + DWORD red; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL); + if (!res) stream->herr=true; + return red/size; +#endif + } + if (stream->pos+toread > stream->len) toread = stream->len-stream->pos; + memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread; + stream->pos += red; + return red/size; +} + + + + +// file_in_zip_read_info_s contain internal information about a file in zipfile, +// when reading and decompress it +typedef struct +{ + char *read_buffer; // internal buffer for compressed data + z_stream stream; // zLib stream structure for inflate + + uLong pos_in_zipfile; // position in byte on the zipfile, for fseek + uLong stream_initialised; // flag set if stream structure is initialised + + uLong offset_local_extrafield;// offset of the local extra field + uInt size_local_extrafield;// size of the local extra field + uLong pos_local_extrafield; // position in the local extra field in read + + uLong crc32; // crc32 of all data uncompressed + uLong crc32_wait; // crc32 we must obtain after decompress all + uLong rest_read_compressed; // number of byte to be decompressed + uLong rest_read_uncompressed;//number of byte to be obtained after decomp + LUFILE* file; // io structore of the zipfile + uLong compression_method; // compression method (0==store) + uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) + bool encrypted; // is it encrypted? + unsigned long keys[3]; // decryption keys, initialized by unzOpenCurrentFile + int encheadleft; // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first + char crcenctest; // if encrypted, we'll check the encryption buffer against this +} file_in_zip_read_info_s; + + +// unz_s contain internal information about the zipfile +typedef struct +{ + LUFILE* file; // io structore of the zipfile + unz_global_info gi; // public global information + uLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx) + uLong num_file; // number of the current file in the zipfile + uLong pos_in_central_dir; // pos of the current file in the central dir + uLong current_file_ok; // flag about the usability of the current file + uLong central_pos; // position of the beginning of the central dir + + uLong size_central_dir; // size of the central directory + uLong offset_central_dir; // offset of start of central directory with respect to the starting disk number + + unz_file_info cur_file_info; // public info about the current file in zip + unz_file_info_internal cur_file_info_internal; // private info about it + file_in_zip_read_info_s* pfile_in_zip_read; // structure about the current file if we are decompressing it +} unz_s, *unzFile; + + +int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity); +// Compare two filename (fileName1,fileName2). + +z_off_t unztell (unzFile file); +// Give the current position in uncompressed data + +int unzeof (unzFile file); +// return 1 if the end of file was reached, 0 elsewhere + +int unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len); +// Read extra field from the current file (opened by unzOpenCurrentFile) +// This is the local-header version of the extra field (sometimes, there is +// more info in the local-header version than in the central-header) +// +// if buf==NULL, it return the size of the local extra field +// +// if buf!=NULL, len is the size of the buffer, the extra header is copied in +// buf. +// the return value is the number of bytes copied in buf, or (if <0) +// the error code + + + +// =========================================================================== +// Read a byte from a gz_stream; update next_in and avail_in. Return EOF +// for end of file. +// IN assertion: the stream s has been sucessfully opened for reading. + +int unzlocal_getByte(LUFILE *fin,int *pi) +{ unsigned char c; + int err = (int)lufread(&c, 1, 1, fin); + if (err==1) + { *pi = (int)c; + return UNZ_OK; + } + else + { if (luferror(fin)) return UNZ_ERRNO; + else return UNZ_EOF; + } +} + + +// =========================================================================== +// Reads a long in LSB order from the given gz_stream. Sets +int unzlocal_getShort (LUFILE *fin,uLong *pX) +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +int unzlocal_getLong (LUFILE *fin,uLong *pX) +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +// My own strcmpi / strcasecmp +int strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= (char)0x20; + if ((c2>='a') && (c2<='z')) + c2 -= (char)0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + + + +// +// Compare two filename (fileName1,fileName2). +// If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) +// If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) +// +int unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity) +{ if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); + else return strcmpcasenosensitive_internal(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + + +// Locate the Central directory of a zipfile (at the end, just before +// the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found, +// rather than 0, since 0 is a valid central-dir-location for an empty zipfile. +uLong unzlocal_SearchCentralDir(LUFILE *fin) +{ if (lufseek(fin,0,SEEK_END) != 0) return 0xFFFFFFFF; + uLong uSizeFile = luftell(fin); + + uLong uMaxBack=0xffff; // maximum size of global comment + if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; + + unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4); + if (buf==NULL) return 0xFFFFFFFF; + uLong uPosFound=0xFFFFFFFF; + + uLong uBackRead = 4; + while (uBackReaduMaxBack) uBackRead = uMaxBack; + else uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (lufseek(fin,uReadPos,SEEK_SET)!=0) break; + if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break; + for (i=(int)uReadSize-3; (i--)>=0;) + { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { uPosFound = uReadPos+i; break; + } + } + if (uPosFound!=0) break; + } + if (buf) zfree(buf); + return uPosFound; +} + + +int unzGoToFirstFile (unzFile file); +int unzCloseCurrentFile (unzFile file); + +// Open a Zip file. +// If the zipfile cannot be opened (file don't exist or in not valid), return NULL. +// Otherwise, the return value is a unzFile Handle, usable with other unzip functions +unzFile unzOpenInternal(LUFILE *fin) +{ if (fin==NULL) return NULL; + if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;} + + int err=UNZ_OK; + unz_s us={0}; + uLong central_pos=0,uL=0; + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0xFFFFFFFF) err=UNZ_ERRNO; + if (err==UNZ_OK && lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO; + // the signature, already checked + if (err==UNZ_OK && unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; + // number of this disk + uLong number_disk=0; // number of the current dist, used for spanning ZIP, unsupported, always 0 + if (err==UNZ_OK && unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; + // number of the disk with the start of the central directory + uLong number_disk_with_CD=0; // number the the disk with central dir, used for spaning ZIP, unsupported, always 0 + if (err==UNZ_OK && unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; + // total number of entries in the central dir on this disk + if (err==UNZ_OK && unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; + // total number of entries in the central dir + uLong number_entry_CD=0; // total number of entries in the central dir (same than number_entry on nospan) + if (err==UNZ_OK && unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; + if (err==UNZ_OK && ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))) err=UNZ_BADZIPFILE; + // size of the central directory + if (err==UNZ_OK && unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; + // offset of start of central directory with respect to the starting disk number + if (err==UNZ_OK && unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; + // zipfile comment length + if (err==UNZ_OK && unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; + if (err==UNZ_OK && ((central_pos+fin->initial_offsetinitial_offset - (us.offset_central_dir+us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + fin->initial_offset = 0; // since the zipfile itself is expected to handle this + + unz_s *s = (unz_s*)zmalloc(sizeof(unz_s)); + *s=us; + unzGoToFirstFile((unzFile)s); + return (unzFile)s; +} + + + +// Close a ZipFile opened with unzipOpen. +// If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), +// these files MUST be closed with unzipCloseCurrentFile before call unzipClose. +// return UNZ_OK if there is no problem. +int unzClose (unzFile file) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + if (s->pfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + lufclose(s->file); + if (s) zfree(s); // unused s=0; + return UNZ_OK; +} + + +// Write info about the ZipFile in the *pglobal_info structure. +// No preparation of the structure is needed +// return UNZ_OK if there is no problem. +int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +// Translate date/time from Dos format to tm_unz (readable more easilty) +void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +// Get Info about the current file in the zipfile, with internal only info +int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize); + +int unzlocal_GetCurrentFileInfoInternal (unzFile file, unz_file_info *pfile_info, + unz_file_info_internal *pfile_info_internal, char *szFileName, + uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + // we check the magic + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + {} // unused lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + //unused lSeek+=file_info.size_file_comment - uSizeRead; + } + else {} //unused lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +// Write info about the ZipFile in the *pglobal_info structure. +// No preparation of the structure is needed +// return UNZ_OK if there is no problem. +int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, szComment,commentBufferSize); +} + + +// Set the current file of the zipfile to the first file. +// return UNZ_OK if there is no problem +int unzGoToFirstFile (unzFile file) +{ + int err; + unz_s* s; + if (file==NULL) return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +// Set the current file of the zipfile to the next file. +// return UNZ_OK if there is no problem +// return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +// Try locate the file szFileName in the zipfile. +// For the iCaseSensitivity signification, see unzStringFileNameCompare +// return value : +// UNZ_OK if the file is found. It becomes the current file. +// UNZ_END_OF_LIST_OF_FILE if the file is not found +int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName,szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +// Read the local header of the current zipfile +// Check the coherency of the local header and info in the end of central +// directory about this file +// store in *piSizeVar the size of extra info in local header +// (filename and size of extra field data) +int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s,uInt *piSizeVar, + uLong *poffset_local_extrafield, uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +// else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) +// err=UNZ_BADZIPFILE; + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + + + + + +// Open for reading data the current file in the zipfile. +// If there is no error and the file is opened, the return value is UNZ_OK. +int unzOpenCurrentFile (unzFile file, const char *password) +{ + int err; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; // offset of the local extra field + uInt size_local_extrafield; // size of the local extra field + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0; + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) + { // unused err=UNZ_BADZIPFILE; + } + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + // windowBits is passed < 0 to tell that there is no zlib header. + // Note that in this case inflate *requires* an extra "dummy" byte + // after the compressed stream in order to complete decompression and + // return Z_STREAM_END. + // In unzip, i don't wait absolutely Z_STREAM_END because I known the + // size of both compressed and uncompressed data + } + pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; + pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0; + bool extlochead = (s->cur_file_info.flag&8)!=0; + if (extlochead) pfile_in_zip_read_info->crcenctest = (char)((s->cur_file_info.dosDate>>8)&0xff); + else pfile_in_zip_read_info->crcenctest = (char)(s->cur_file_info.crc >> 24); + pfile_in_zip_read_info->encheadleft = (pfile_in_zip_read_info->encrypted?12:0); + pfile_in_zip_read_info->keys[0] = 305419896L; + pfile_in_zip_read_info->keys[1] = 591751049L; + pfile_in_zip_read_info->keys[2] = 878082192L; + for (const char *cp=password; cp!=0 && *cp!=0; cp++) Uupdate_keys(pfile_in_zip_read_info->keys,*cp); + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + + return UNZ_OK; +} + + +// Read bytes from the current file. +// buf contain buffer where data must be copied +// len the size of buf. +// return the number of byte copied if somes bytes are copied (and also sets *reached_eof) +// return 0 if the end of file was reached. (and also sets *reached_eof). +// return <0 with error code if there is an error. (in which case *reached_eof is meaningless) +// (UNZ_ERRNO for IO error, or zLib error for uncompress error) +int unzReadCurrentFile (unzFile file, voidp buf, unsigned len, bool *reached_eof) +{ int err=UNZ_OK; + uInt iRead = 0; + if (reached_eof!=0) *reached_eof=false; + + unz_s *s = (unz_s*)file; + if (s==NULL) return UNZ_PARAMERROR; + + file_in_zip_read_info_s* pfile_in_zip_read_info = s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; + if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; + if (len==0) return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + } + + while (pfile_in_zip_read_info->stream.avail_out>0) + { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) + { uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) {if (reached_eof!=0) *reached_eof=true; return UNZ_EOF;} + if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO; + if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + pfile_in_zip_read_info->stream.next_in = (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + // + if (pfile_in_zip_read_info->encrypted) + { char *buf = (char*)pfile_in_zip_read_info->stream.next_in; + for (unsigned int i=0; ikeys,buf[i]); + } + } + + unsigned int uDoEncHead = pfile_in_zip_read_info->encheadleft; + if (uDoEncHead>pfile_in_zip_read_info->stream.avail_in) uDoEncHead=pfile_in_zip_read_info->stream.avail_in; + if (uDoEncHead>0) + { char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1]; + pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead; + pfile_in_zip_read_info->stream.avail_in -= uDoEncHead; + pfile_in_zip_read_info->stream.next_in += uDoEncHead; + pfile_in_zip_read_info->encheadleft -= uDoEncHead; + if (pfile_in_zip_read_info->encheadleft==0) + { if (bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD; + } + } + + if (pfile_in_zip_read_info->compression_method==0) + { uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) + { uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + } + else + { uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + } + for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); + pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,pfile_in_zip_read_info->stream.next_out,uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + if (pfile_in_zip_read_info->rest_read_uncompressed==0) {if (reached_eof!=0) *reached_eof=true;} + } + else + { uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + // + err=inflate(&pfile_in_zip_read_info->stream,flush); + // + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,bufBefore,(uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + if (err==Z_STREAM_END || pfile_in_zip_read_info->rest_read_uncompressed==0) + { if (reached_eof!=0) *reached_eof=true; + return iRead; + } + if (err!=Z_OK) break; + } + } + + if (err==Z_OK) return iRead; + return err; +} + + +// Give the current position in uncompressed data +z_off_t unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +// return 1 if the end of file was reached, 0 elsewhere +int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +// Read extra field from the current file (opened by unzOpenCurrentFile) +// This is the local-header version of the extra field (sometimes, there is +// more info in the local-header version than in the central-header) +// if buf==NULL, it return the size of the local extra field that can be read +// if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. +// the return value is the number of bytes copied in buf, or (if <0) the error code +int unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +// Close the file in zip opened with unzipOpenCurrentFile +// Return UNZ_CRCERROR if all the file was read but the CRC is not good +int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + if (pfile_in_zip_read_info->read_buffer!=0) + { void *buf = pfile_in_zip_read_info->read_buffer; + zfree(buf); + pfile_in_zip_read_info->read_buffer=0; + } + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; + + s->pfile_in_zip_read=NULL; + + return err; +} + + +// Get the global comment string of the ZipFile, in the szComment buffer. +// uSizeBuf is the size of the szComment buffer. +// return the number of byte copied or an error code <0 +int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ //int err=UNZ_OK; + unz_s* s; + uLong uReadThis ; + if (file==NULL) return UNZ_PARAMERROR; + s=(unz_s*)file; + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; + if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO; + if (uReadThis>0) + { *szComment='\0'; + if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO; + } + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + + + + + +int unzOpenCurrentFile (unzFile file, const char *password); +int unzReadCurrentFile (unzFile file, void *buf, unsigned len); +int unzCloseCurrentFile (unzFile file); + + + + +class TUnzip +{ public: + TUnzip(const char *pwd) : uf(0), unzbuf(0), currentfile(-1), czei(-1), password(0) {if (pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} + ~TUnzip() {if (password!=0) delete[] password; password=0; if (unzbuf!=0) delete[] unzbuf; unzbuf=0;} + + unzFile uf; int currentfile; ZIPENTRY cze; int czei; + char *password; + char *unzbuf; // lazily created and destroyed, used by Unzip + TCHAR rootdir[MAX_PATH]; // includes a trailing slash + + ZRESULT Open(void *z,unsigned int len,DWORD flags); + ZRESULT Get(int index,ZIPENTRY *ze); + ZRESULT Find(const TCHAR *name,bool ic,int *index,ZIPENTRY *ze); + ZRESULT Unzip(int index,void *dst,unsigned int len,DWORD flags); + ZRESULT SetUnzipBaseDir(const TCHAR *dir); + ZRESULT Close(); +}; + + +ZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags) +{ if (uf!=0 || currentfile!=-1) return ZR_NOTINITED; + // +#ifdef ZIP_STD + getcwd(rootdir,MAX_PATH-1); +#else +#ifdef GetCurrentDirectory + GetCurrentDirectory(MAX_PATH-1,rootdir); +#else + rootdir[0]='/'; rootdir[1]=0; +#endif +#endif + TCHAR *lastchar = &rootdir[_tcslen(rootdir)-1]; + if (*lastchar!='\\' && *lastchar!='/') {lastchar[1]='/'; lastchar[2]=0;} + // + if (flags==ZIP_HANDLE) + { // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE. + DWORD res = GetFilePosU((HANDLE)z); + bool canseek = (res!=0xFFFFFFFF); + if (!canseek) return ZR_SEEK; + } + ZRESULT e; LUFILE *f = lufopen(z,len,flags,&e); + if (f==NULL) return e; + uf = unzOpenInternal(f); + if (uf==0) return ZR_NOFILE; + return ZR_OK; +} + +ZRESULT TUnzip::SetUnzipBaseDir(const TCHAR *dir) +{ _tcsncpy(rootdir,dir,MAX_PATH-1); + TCHAR *lastchar = &rootdir[_tcslen(rootdir)-1]; + if (*lastchar!='\\' && *lastchar!='/') {lastchar[1]='/'; lastchar[2]=0;} + return ZR_OK; +} + +ZRESULT TUnzip::Get(int index,ZIPENTRY *ze) +{ if (index<-1 || index>=(int)uf->gi.number_entry) return ZR_ARGS; + if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; + if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;} + if (index==-1) + { ze->index = uf->gi.number_entry; + ze->name[0]=0; + ze->attr=0; +#ifdef ZIP_STD + ze->atime=0; + ze->ctime=0; + ze->mtime=0; +#else + ze->atime.dwLowDateTime=0; ze->atime.dwHighDateTime=0; + ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0; + ze->mtime.dwLowDateTime=0; ze->mtime.dwHighDateTime=0; +#endif + ze->comp_size=0; + ze->unc_size=0; + return ZR_OK; + } + if (index<(int)uf->num_file) unzGoToFirstFile(uf); + while ((int)uf->num_filefile,offset,SEEK_SET)!=0) return ZR_READ; + unsigned char *extra = new unsigned char[extralen]; + if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;} + // + ze->index=uf->num_file; + TCHAR tfn[MAX_PATH]; +#ifdef UNICODE + MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH); +#else + strcpy(tfn,fn); +#endif + // As a safety feature: if the zip filename had sneaky stuff + // like "c:\windows\file.txt" or "\windows\file.txt" or "fred\..\..\..\windows\file.txt" + // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name), + // it won't be a problem. (If the programmer really did want to get the full evil information, + // then they can edit out this security feature from here). + // In particular, we chop off any prefixes that are "c:\" or "\" or "/" or "[stuff]\.." or "[stuff]/.." + const TCHAR *sfn=tfn; + for (;;) + { if (sfn[0]!=0 && sfn[1]==':') {sfn+=2; continue;} + if (sfn[0]=='\\') {sfn++; continue;} + if (sfn[0]=='/') {sfn++; continue;} + const TCHAR *c; + c=_tcsstr(sfn,_T("\\..\\")); if (c!=0) {sfn=c+4; continue;} + c=_tcsstr(sfn,_T("\\../")); if (c!=0) {sfn=c+4; continue;} + c=_tcsstr(sfn,_T("/../")); if (c!=0) {sfn=c+4; continue;} + c=_tcsstr(sfn,_T("/..\\")); if (c!=0) {sfn=c+4; continue;} + break; + } + _tcsncpy(ze->name, sfn,MAX_PATH); + + + unsigned long a = ufi.external_fa; + // zip has an 'attribute' 32bit value. Its lower half is windows stuff + // its upper half is standard unix stat.st_mode. We'll start trying + // to read it in unix mode + bool isdir = (a&0x40000000)!=0; + bool readonly= (a&0x00800000)==0; + //bool readable= (a&0x01000000)!=0; // unused + //bool executable=(a&0x00400000)!=0; // unused + bool hidden=false, system=false, archive=true; + // but in normal hostmodes these are overridden by the lower half... + int host = ufi.version>>8; + if (host==0 || host==7 || host==11 || host==14) + { readonly= (a&0x00000001)!=0; + hidden= (a&0x00000002)!=0; + system= (a&0x00000004)!=0; + isdir= (a&0x00000010)!=0; + archive= (a&0x00000020)!=0; + } + readonly; hidden; system; isdir; archive; + ze->attr=0; +#ifdef ZIP_STD + ze->attr = (a&0xFFFF0000)>>16; + if (isdir) ze->attr |= S_IFDIR; + if (readonly) ze->attr &= ~S_IWUSR; +#else + if (isdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; + if (archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE; + if (hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN; + if (readonly) ze->attr|=FILE_ATTRIBUTE_READONLY; + if (system) ze->attr|=FILE_ATTRIBUTE_SYSTEM; +#endif + ze->comp_size = ufi.compressed_size; + ze->unc_size = ufi.uncompressed_size; + // + WORD dostime = (WORD)(ufi.dosDate&0xFFFF); + WORD dosdate = (WORD)((ufi.dosDate>>16)&0xFFFF); + FILETIME ftd = dosdatetime2filetime(dosdate,dostime); + FILETIME ft; LocalFileTimeToFileTime(&ftd,&ft); + ze->atime=ft; ze->ctime=ft; ze->mtime=ft; + // the zip will always have at least that dostime. But if it also has + // an extra header, then we'll instead get the info from that. + unsigned int epos=0; + while (epos+4mtime = timet2filetime(mtime); + } + if (hasatime) + { lutime_t atime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); + epos+=4; + ze->atime = timet2filetime(atime); + } + if (hasctime) + { lutime_t ctime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24); + epos+=4; + ze->ctime = timet2filetime(ctime); + } + break; + } + // + if (extra!=0) delete[] extra; + memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index; + return ZR_OK; +} + +ZRESULT TUnzip::Find(const TCHAR *tname,bool ic,int *index,ZIPENTRY *ze) +{ char name[MAX_PATH]; +#ifdef UNICODE + WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0); +#else + strcpy(name,tname); +#endif + int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE); + if (res!=UNZ_OK) + { if (index!=0) *index=-1; + if (ze!=NULL) {memset(ze,0,sizeof(ZIPENTRY)); ze->index=-1;} + return ZR_NOTFOUND; + } + if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; + int i = (int)uf->num_file; + if (index!=NULL) *index=i; + if (ze!=NULL) + { ZRESULT zres = Get(i,ze); + if (zres!=ZR_OK) return zres; + } + return ZR_OK; +} + +void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) +{ // first check that rootdir exists. nb. rootdir has a trailing slash + if (rootdir!=0) + { TCHAR rd[MAX_PATH]; _tcsncpy(rd,rootdir,MAX_PATH); size_t len=_tcslen(rd); + if (len>0 && (rd[len-1]=='/' || rd[len-1]=='\\')) rd[len-1]=0; +#ifdef ZIP_STD + if (!FileExists(rd)) lumkdir(rd); +#else + if (!FileExists(rd)) CreateDirectory(rd,0); +#endif + } + if (*dir==0) return; + const TCHAR *lastslash=dir, *c=lastslash; + while (*c!=0) {if (*c=='/' || *c=='\\') lastslash=c; c++;} + const TCHAR *name=lastslash; + if (lastslash!=dir) + { TCHAR tmp[MAX_PATH]; memcpy(tmp,dir,sizeof(TCHAR)*(lastslash-dir)); + tmp[lastslash-dir]=0; + EnsureDirectory(rootdir,tmp); + name++; + } + TCHAR cd[MAX_PATH]; *cd=0; if (rootdir!=0) _tcsncpy(cd,rootdir,MAX_PATH); cd[MAX_PATH-1]=0; + size_t len=_tcslen(cd); _tcsncpy(cd+len,dir,MAX_PATH-len); cd[MAX_PATH-1]=0; +#ifdef ZIP_STD + if (!FileExists(cd)) lumkdir(cd); +#else + if (!FileExists(cd)) + { CreateDirectory(cd,0); + } +#endif +} + + + +ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) +{ if (flags!=ZIP_MEMORY && flags!=ZIP_FILENAME && flags!=ZIP_HANDLE) return ZR_ARGS; + if (flags==ZIP_MEMORY) + { if (index!=currentfile) + { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; + if (index>=(int)uf->gi.number_entry) return ZR_ARGS; + if (index<(int)uf->num_file) unzGoToFirstFile(uf); + while ((int)uf->num_file0) return ZR_MORE; + if (res==UNZ_PASSWORD) return ZR_PASSWORD; + return ZR_FLATE; + } + // otherwise we're writing to a handle or a file + if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; + if (index>=(int)uf->gi.number_entry) return ZR_ARGS; + if (index<(int)uf->num_file) unzGoToFirstFile(uf); + while ((int)uf->num_file0) {size_t writ=fwrite(unzbuf,1,res,h); if (writ<(size_t)res) {haderr=ZR_WRITE; break;}} +#else + if (res>0) {DWORD writ; BOOL bres=WriteFile(h,unzbuf,res,&writ,NULL); if (!bres) {haderr=ZR_WRITE; break;}} +#endif + if (reached_eof) break; + if (res==0) {haderr=ZR_FLATE; break;} + } + unzCloseCurrentFile(uf); +#ifdef ZIP_STD + if (flags!=ZIP_HANDLE) fclose(h); + if (*fn!=0) {struct utimbuf ubuf; ubuf.actime=ze.atime; ubuf.modtime=ze.mtime; utime(fn,&ubuf);} +#else + if (!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe + if (flags!=ZIP_HANDLE) CloseHandle(h); +#endif + if (haderr!=0) return haderr; + return ZR_OK; +} + +ZRESULT TUnzip::Close() +{ if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1; + if (uf!=0) unzClose(uf); uf=0; + return ZR_OK; +} + + + + + +ZRESULT lasterrorU=ZR_OK; + +unsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len) +{ if (code==ZR_RECENT) code=lasterrorU; + const TCHAR *msg=_T("unknown zip result code"); + switch (code) + { case ZR_OK: msg=_T("Success"); break; + case ZR_NODUPH: msg=_T("Culdn't duplicate handle"); break; + case ZR_NOFILE: msg=_T("Couldn't create/open file"); break; + case ZR_NOALLOC: msg=_T("Failed to allocate memory"); break; + case ZR_WRITE: msg=_T("Error writing to file"); break; + case ZR_NOTFOUND: msg=_T("File not found in the zipfile"); break; + case ZR_MORE: msg=_T("Still more data to unzip"); break; + case ZR_CORRUPT: msg=_T("Zipfile is corrupt or not a zipfile"); break; + case ZR_READ: msg=_T("Error reading file"); break; + case ZR_PASSWORD: msg=_T("Correct password required"); break; + case ZR_ARGS: msg=_T("Caller: faulty arguments"); break; + case ZR_PARTIALUNZ: msg=_T("Caller: the file had already been partially unzipped"); break; + case ZR_NOTMMAP: msg=_T("Caller: can only get memory of a memory zipfile"); break; + case ZR_MEMSIZE: msg=_T("Caller: not enough space allocated for memory zipfile"); break; + case ZR_FAILED: msg=_T("Caller: there was a previous error"); break; + case ZR_ENDED: msg=_T("Caller: additions to the zip have already been ended"); break; + case ZR_ZMODE: msg=_T("Caller: mixing creation and opening of zip"); break; + case ZR_NOTINITED: msg=_T("Zip-bug: internal initialisation not completed"); break; + case ZR_SEEK: msg=_T("Zip-bug: trying to seek the unseekable"); break; + case ZR_MISSIZE: msg=_T("Zip-bug: the anticipated size turned out wrong"); break; + case ZR_NOCHANGE: msg=_T("Zip-bug: tried to change mind, but not allowed"); break; + case ZR_FLATE: msg=_T("Zip-bug: an internal error during flation"); break; + } + unsigned int mlen=(unsigned int)_tcslen(msg); + if (buf==0 || len==0) return mlen; + unsigned int n=mlen; if (n+1>len) n=len-1; + _tcsncpy(buf,msg,n); buf[n]=0; + return mlen; +} + + +typedef struct +{ DWORD flag; + TUnzip *unz; +} TUnzipHandleData; + +HZIP OpenZipInternal(void *z,unsigned int len,DWORD flags, const char *password) +{ TUnzip *unz = new TUnzip(password); + lasterrorU = unz->Open(z,len,flags); + if (lasterrorU!=ZR_OK) {delete unz; return 0;} + TUnzipHandleData *han = new TUnzipHandleData; + han->flag=1; han->unz=unz; return (HZIP)han; +} +HZIP OpenZipHandle(HANDLE h, const char *password) {return OpenZipInternal((void*)h,0,ZIP_HANDLE,password);} +HZIP OpenZip(const TCHAR *fn, const char *password) {return OpenZipInternal((void*)fn,0,ZIP_FILENAME,password);} +HZIP OpenZip(void *z,unsigned int len, const char *password) {return OpenZipInternal(z,len,ZIP_MEMORY,password);} + + +ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze) +{ ze->index=0; *ze->name=0; ze->unc_size=0; + if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->Get(index,ze); + return lasterrorU; +} + +ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) +{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->Find(name,ic,index,ze); + return lasterrorU; +} + +ZRESULT UnzipItemInternal(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) +{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->Unzip(index,dst,len,flags); + return lasterrorU; +} +ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h) {return UnzipItemInternal(hz,index,(void*)h,0,ZIP_HANDLE);} +ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn) {return UnzipItemInternal(hz,index,(void*)fn,0,ZIP_FILENAME);} +ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len) {return UnzipItemInternal(hz,index,z,len,ZIP_MEMORY);} + +ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir) +{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->SetUnzipBaseDir(dir); + return lasterrorU; +} + + +ZRESULT CloseZipU(HZIP hz) +{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;} + TUnzipHandleData *han = (TUnzipHandleData*)hz; + if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;} + TUnzip *unz = han->unz; + lasterrorU = unz->Close(); + delete unz; + delete han; + return lasterrorU; +} + +bool IsZipHandleU(HZIP hz) +{ if (hz==0) return false; + TUnzipHandleData *han = (TUnzipHandleData*)hz; + return (han->flag==1); +} + + diff --git a/datafile/zip/unzip.h b/datafile/zip/unzip.h new file mode 100644 index 0000000..08a87f0 --- /dev/null +++ b/datafile/zip/unzip.h @@ -0,0 +1,226 @@ +#ifndef _unzip_H +#define _unzip_H +// +#ifdef ZIP_STD +#include +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif +typedef unsigned long DWORD; +typedef char TCHAR; +typedef FILE* HANDLE; +typedef time_t FILETIME; +#endif + +// UNZIPPING functions -- for unzipping. +// This file is a repackaged form of extracts from the zlib code available +// at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original +// copyright notice may be found in unzip.cpp. The repackaging was done +// by Lucian Wischik to simplify and extend its use in Windows/C++. Also +// encryption and unicode filenames have been added. + + +#ifndef _zip_H +DECLARE_HANDLE(HZIP); +#endif +// An HZIP identifies a zip file that has been opened + +typedef DWORD ZRESULT; +// return codes from any of the zip functions. Listed later. + +typedef struct +{ int index; // index of this file within the zip + TCHAR name[MAX_PATH]; // filename within the zip + DWORD attr; // attributes, as in GetFileAttributes. + FILETIME atime,ctime,mtime;// access, create, modify filetimes + long comp_size; // sizes of item, compressed and uncompressed. These + long unc_size; // may be -1 if not yet known (e.g. being streamed in) +} ZIPENTRY; + + +HZIP OpenZip(const TCHAR *fn, const char *password); +HZIP OpenZip(void *z,unsigned int len, const char *password); +HZIP OpenZipHandle(HANDLE h, const char *password); +// OpenZip - opens a zip file and returns a handle with which you can +// subsequently examine its contents. You can open a zip file from: +// from a pipe: OpenZipHandle(hpipe_read,0); +// from a file (by handle): OpenZipHandle(hfile,0); +// from a file (by name): OpenZip("c:\\test.zip","password"); +// from a memory block: OpenZip(bufstart, buflen,0); +// If the file is opened through a pipe, then items may only be +// accessed in increasing order, and an item may only be unzipped once, +// although GetZipItem can be called immediately before and after unzipping +// it. If it's opened in any other way, then full random access is possible. +// Note: pipe input is not yet implemented. +// Note: zip passwords are ascii, not unicode. +// Note: for windows-ce, you cannot close the handle until after CloseZip. +// but for real windows, the zip makes its own copy of your handle, so you +// can close yours anytime. + +ZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze); +// GetZipItem - call this to get information about an item in the zip. +// If index is -1 and the file wasn't opened through a pipe, +// then it returns information about the whole zipfile +// (and in particular ze.index returns the number of index items). +// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) +// See below for notes on what happens when you unzip such an item. +// Note: if you are opening the zip through a pipe, then random access +// is not possible and GetZipItem(-1) fails and you can't discover the number +// of items except by calling GetZipItem on each one of them in turn, +// starting at 0, until eventually the call fails. Also, in the event that +// you are opening through a pipe and the zip was itself created into a pipe, +// then then comp_size and sometimes unc_size as well may not be known until +// after the item has been unzipped. + +ZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); +// FindZipItem - finds an item by name. ic means 'insensitive to case'. +// It returns the index of the item, and returns information about it. +// If nothing was found, then index is set to -1 and the function returns +// an error code. + +ZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn); +ZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len); +ZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h); +// UnzipItem - given an index to an item, unzips it. You can unzip to: +// to a pipe: UnzipItemHandle(hz,i, hpipe_write); +// to a file (by handle): UnzipItemHandle(hz,i, hfile); +// to a file (by name): UnzipItem(hz,i, ze.name); +// to a memory block: UnzipItem(hz,i, buf,buflen); +// In the final case, if the buffer isn't large enough to hold it all, +// then the return code indicates that more is yet to come. If it was +// large enough, and you want to know precisely how big, GetZipItem. +// Note: zip files are normally stored with relative pathnames. If you +// unzip with ZIP_FILENAME a relative pathname then the item gets created +// relative to the current directory - it first ensures that all necessary +// subdirectories have been created. Also, the item may itself be a directory. +// If you unzip a directory with ZIP_FILENAME, then the directory gets created. +// If you unzip it to a handle or a memory block, then nothing gets created +// and it emits 0 bytes. +ZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir); +// if unzipping to a filename, and it's a relative filename, then it will be relative to here. +// (defaults to current-directory). + + +ZRESULT CloseZip(HZIP hz); +// CloseZip - the zip handle must be closed with this function. + +unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); +// FormatZipMessage - given an error code, formats it as a string. +// It returns the length of the error message. If buf/len points +// to a real buffer, then it also writes as much as possible into there. + + +// These are the result codes: +#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, +#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. +// The following come from general system stuff (e.g. files not openable) +#define ZR_GENMASK 0x0000FF00 +#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle +#define ZR_NOFILE 0x00000200 // couldn't create/open the file +#define ZR_NOALLOC 0x00000300 // failed to allocate some resource +#define ZR_WRITE 0x00000400 // a general error writing to the file +#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip +#define ZR_MORE 0x00000600 // there's still more data to be unzipped +#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile +#define ZR_READ 0x00000800 // a general error reading the file +#define ZR_PASSWORD 0x00001000 // we didn't get the right password to unzip the file +// The following come from mistakes on the part of the caller +#define ZR_CALLERMASK 0x00FF0000 +#define ZR_ARGS 0x00010000 // general mistake with the arguments +#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't +#define ZR_MEMSIZE 0x00030000 // the memory size is too small +#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function +#define ZR_ENDED 0x00050000 // the zip creation has already been closed +#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken +#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped +#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip +// The following come from bugs within the zip library itself +#define ZR_BUGMASK 0xFF000000 +#define ZR_NOTINITED 0x01000000 // initialisation didn't work +#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file +#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed +#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code + + + + + +// e.g. +// +// SetCurrentDirectory("c:\\docs\\stuff"); +// HZIP hz = OpenZip("c:\\stuff.zip",0); +// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; +// for (int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zip.h" +// +typedef unsigned short WORD; +#define _tcslen strlen +#define _tcsicmp stricmp +#define _tcsncpy strncpy +#define _tcsstr strstr +#define INVALID_HANDLE_VALUE 0 +#ifndef _T +#define _T(s) s +#endif +#ifndef S_IWUSR +#define S_IWUSR 0000200 +#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif + +// +#else +#include +#include +#include +#include +#include "zip.h" +#endif + + +// THIS FILE is almost entirely based upon code by info-zip. +// It has been modified by Lucian Wischik. The modifications +// were a complete rewrite of the bit of code that generates the +// layout of the zipfile, and support for zipping to/from memory +// or handles or pipes or pagefile or diskfiles, encryption, unicode. +// The original code may be found at http://www.info-zip.org +// The original copyright text follows. +// +// +// +// This is version 1999-Oct-05 of the Info-ZIP copyright and license. +// The definitive version of this document should be available at +// ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely. +// +// Copyright (c) 1990-1999 Info-ZIP. All rights reserved. +// +// For the purposes of this copyright and license, "Info-ZIP" is defined as +// the following set of individuals: +// +// Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, +// Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, +// Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, David Kirschbaum, +// Johnny Lee, Onno van der Linden, Igor Mandrichenko, Steve P. Miller, +// Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, Kai Uwe Rommel, +// Steve Salisbury, Dave Smith, Christian Spieler, Antoine Verheijen, +// Paul von Behren, Rich Wales, Mike White +// +// This software is provided "as is," without warranty of any kind, express +// or implied. In no event shall Info-ZIP or its contributors be held liable +// for any direct, indirect, incidental, special or consequential damages +// arising out of the use of or inability to use this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. Redistributions of source code must retain the above copyright notice, +// definition, disclaimer, and this list of conditions. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, definition, disclaimer, and this list of conditions in +// documentation and/or other materials provided with the distribution. +// +// 3. Altered versions--including, but not limited to, ports to new operating +// systems, existing ports with new graphical interfaces, and dynamic, +// shared, or static library versions--must be plainly marked as such +// and must not be misrepresented as being the original source. Such +// altered versions also must not be misrepresented as being Info-ZIP +// releases--including, but not limited to, labeling of the altered +// versions with the names "Info-ZIP" (or any variation thereof, including, +// but not limited to, different capitalizations), "Pocket UnZip," "WiZ" +// or "MacZip" without the explicit permission of Info-ZIP. Such altered +// versions are further prohibited from misrepresentative use of the +// Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s). +// +// 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," +// "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and +// binary releases. +// + + +typedef unsigned char uch; // unsigned 8-bit value +typedef unsigned short ush; // unsigned 16-bit value +typedef unsigned long ulg; // unsigned 32-bit value +typedef size_t extent; // file size +typedef unsigned Pos; // must be at least 32 bits +typedef unsigned IPos; // A Pos is an index in the character window. Pos is used only for parameter passing + +#ifndef EOF +#define EOF (-1) +#endif + + + + + + +// Error return values. The values 0..4 and 12..18 follow the conventions +// of PKZIP. The values 4..10 are all assigned to "insufficient memory" +// by PKZIP, so the codes 5..10 are used here for other purposes. +#define ZE_MISS -1 // used by procname(), zipbare() +#define ZE_OK 0 // success +#define ZE_EOF 2 // unexpected end of zip file +#define ZE_FORM 3 // zip file structure error +#define ZE_MEM 4 // out of memory +#define ZE_LOGIC 5 // internal logic error +#define ZE_BIG 6 // entry too large to split +#define ZE_NOTE 7 // invalid comment format +#define ZE_TEST 8 // zip test (-T) failed or out of memory +#define ZE_ABORT 9 // user interrupt or termination +#define ZE_TEMP 10 // error using a temp file +#define ZE_READ 11 // read or seek error +#define ZE_NONE 12 // nothing to do +#define ZE_NAME 13 // missing or empty zip file +#define ZE_WRITE 14 // error writing to a file +#define ZE_CREAT 15 // couldn't open to write +#define ZE_PARMS 16 // bad command line +#define ZE_OPEN 18 // could not open a specified file to read +#define ZE_MAXERR 18 // the highest error number + + +// internal file attribute +#define UNKNOWN (-1) +#define BINARY 0 +#define ASCII 1 + +#define BEST -1 // Use best method (deflation or store) +#define STORE 0 // Store method +#define DEFLATE 8 // Deflation method + +#define CRCVAL_INITIAL 0L + +// MSDOS file or directory attributes +#define MSDOS_HIDDEN_ATTR 0x02 +#define MSDOS_DIR_ATTR 0x10 + +// Lengths of headers after signatures in bytes +#define LOCHEAD 26 +#define CENHEAD 42 +#define ENDHEAD 18 + +// Definitions for extra field handling: +#define EB_HEADSIZE 4 /* length of a extra field block header */ +#define EB_LEN 2 /* offset of data length field in header */ +#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */ +#define EB_UT_FLAGS 0 /* byte offset of Flags field */ +#define EB_UT_TIME1 1 /* byte offset of 1st time value */ +#define EB_UT_FL_MTIME (1 << 0) /* mtime present */ +#define EB_UT_FL_ATIME (1 << 1) /* atime present */ +#define EB_UT_FL_CTIME (1 << 2) /* ctime present */ +#define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n)) +#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3)) +#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1)) + + +// Macros for writing machine integers to little-endian format +#define PUTSH(a,f) {char _putsh_c=(char)((a)&0xff); wfunc(param,&_putsh_c,1); _putsh_c=(char)((a)>>8); wfunc(param,&_putsh_c,1);} +#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))} + + +// -- Structure of a ZIP file -- +// Signatures for zip file information headers +#define LOCSIG 0x04034b50L +#define CENSIG 0x02014b50L +#define ENDSIG 0x06054b50L +#define EXTLOCSIG 0x08074b50L + + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +// The minimum and maximum match lengths + + +#define WSIZE (0x8000) +// Maximum window size = 32K. If you are really short of memory, compile +// with a smaller WSIZE but this reduces the compression ratio for files +// of size > WSIZE. WSIZE must be a power of two in the current implementation. +// + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +// Minimum amount of lookahead, except at the end of the input file. +// See deflate.c for comments about the MIN_MATCH+1. +// + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +// In order to simplify the code, particularly on 16 bit machines, match +// distances are limited to MAX_DIST instead of WSIZE. +// + + +#define ZIP_HANDLE 1 +#define ZIP_FILENAME 2 +#define ZIP_MEMORY 3 +#define ZIP_FOLDER 4 + + + +// =========================================================================== +// Constants +// + +#define MAX_BITS 15 +// All codes must not exceed MAX_BITS bits + +#define MAX_BL_BITS 7 +// Bit length codes must not exceed MAX_BL_BITS bits + +#define LENGTH_CODES 29 +// number of length codes, not counting the special END_BLOCK code + +#define LITERALS 256 +// number of literal bytes 0..255 + +#define END_BLOCK 256 +// end of block literal code + +#define L_CODES (LITERALS+1+LENGTH_CODES) +// number of Literal or Length codes, including the END_BLOCK code + +#define D_CODES 30 +// number of distance codes + +#define BL_CODES 19 +// number of codes used to transfer the bit lengths + + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +// The three kinds of block type + +#define LIT_BUFSIZE 0x8000 +#define DIST_BUFSIZE LIT_BUFSIZE +// Sizes of match buffers for literals/lengths and distances. There are +// 4 reasons for limiting LIT_BUFSIZE to 64K: +// - frequencies can be kept in 16 bit counters +// - if compression is not successful for the first block, all input data is +// still in the window so we can still emit a stored block even when input +// comes from standard input. (This can also be done for all blocks if +// LIT_BUFSIZE is not greater than 32K.) +// - if compression is not successful for a file smaller than 64K, we can +// even emit a stored file instead of a stored block (saving 5 bytes). +// - creating new Huffman trees less frequently may not provide fast +// adaptation to changes in the input data statistics. (Take for +// example a binary file with poorly compressible code followed by +// a highly compressible string table.) Smaller buffer sizes give +// fast adaptation but have of course the overhead of transmitting trees +// more frequently. +// - I can't count above 4 +// The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save +// memory at the expense of compression). Some optimizations would be possible +// if we rely on DIST_BUFSIZE == LIT_BUFSIZE. +// + +#define REP_3_6 16 +// repeat previous bit length 3-6 times (2 bits of repeat count) + +#define REPZ_3_10 17 +// repeat a zero length 3-10 times (3 bits of repeat count) + +#define REPZ_11_138 18 +// repeat a zero length 11-138 times (7 bits of repeat count) + +#define HEAP_SIZE (2*L_CODES+1) +// maximum heap size + + +// =========================================================================== +// Local data used by the "bit string" routines. +// + +#define Buf_size (8 * 2*sizeof(char)) +// Number of bits used within bi_buf. (bi_buf may be implemented on +// more than 16 bits on some systems.) + +// Output a 16 bit value to the bit stream, lower (oldest) byte first +#define PUTSHORT(state,w) \ +{ if (state.bs.out_offset >= state.bs.out_size-1) \ + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ + state.bs.out_buf[state.bs.out_offset++] = (char) ((w) & 0xff); \ + state.bs.out_buf[state.bs.out_offset++] = (char) ((ush)(w) >> 8); \ +} + +#define PUTBYTE(state,b) \ +{ if (state.bs.out_offset >= state.bs.out_size) \ + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); \ + state.bs.out_buf[state.bs.out_offset++] = (char) (b); \ +} + +// DEFLATE.CPP HEADER + +#define HASH_BITS 15 +// For portability to 16 bit machines, do not use values above 15. + +#define HASH_SIZE (unsigned)(1<= HASH_BITS + +#define max_insert_length max_lazy_match +// Insert new strings in the hash table only if the match length +// is not greater than this length. This saves time but degrades compression. +// max_insert_length is used only for compression levels <= 3. + + + +const int extra_lbits[LENGTH_CODES] // extra bits for each length code + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +const int extra_dbits[D_CODES] // extra bits for each distance code + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +const int extra_blbits[BL_CODES]// extra bits for each bit length code + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +// The lengths of the bit length codes are sent in order of decreasing +// probability, to avoid transmitting the lengths for unused bit length codes. + + +typedef struct config { + ush good_length; // reduce lazy search above this match length + ush max_lazy; // do not perform lazy search above this match length + ush nice_length; // quit search above this match length + ush max_chain; +} config; + +// Values for max_lazy_match, good_match, nice_match and max_chain_length, +// depending on the desired pack level (0..9). The values given below have +// been tuned to exclude worst case performance for pathological files. +// Better values may be found for specific files. +// + +const config configuration_table[10] = { +// good lazy nice chain + {0, 0, 0, 0}, // 0 store only + {4, 4, 8, 4}, // 1 maximum speed, no lazy matches + {4, 5, 16, 8}, // 2 + {4, 6, 32, 32}, // 3 + {4, 4, 16, 16}, // 4 lazy matches */ + {8, 16, 32, 32}, // 5 + {8, 16, 128, 128}, // 6 + {8, 32, 128, 256}, // 7 + {32, 128, 258, 1024}, // 8 + {32, 258, 258, 4096}};// 9 maximum compression */ + +// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 +// For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning. + + + + + + + +// Data structure describing a single value and its code string. +typedef struct ct_data { + union { + ush freq; // frequency count + ush code; // bit string + } fc; + union { + ush dad; // father node in Huffman tree + ush len; // length of bit string + } dl; +} ct_data; + +typedef struct tree_desc { + ct_data *dyn_tree; // the dynamic tree + ct_data *static_tree; // corresponding static tree or NULL + const int *extra_bits; // extra bits for each code or NULL + int extra_base; // base index for extra_bits + int elems; // max number of elements in the tree + int max_length; // max bit length for the codes + int max_code; // largest code with non zero frequency +} tree_desc; + + + + +class TTreeState +{ public: + TTreeState(); + + ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree + ct_data dyn_dtree[2*D_CODES+1]; // distance tree + ct_data static_ltree[L_CODES+2]; // the static literal tree... + // ... Since the bit lengths are imposed, there is no need for the L_CODES + // extra codes used during heap construction. However the codes 286 and 287 + // are needed to build a canonical tree (see ct_init below). + ct_data static_dtree[D_CODES]; // the static distance tree... + // ... (Actually a trivial tree since all codes use 5 bits.) + ct_data bl_tree[2*BL_CODES+1]; // Huffman tree for the bit lengths + + tree_desc l_desc; + tree_desc d_desc; + tree_desc bl_desc; + + ush bl_count[MAX_BITS+1]; // number of codes at each bit length for an optimal tree + + int heap[2*L_CODES+1]; // heap used to build the Huffman trees + int heap_len; // number of elements in the heap + int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + uch depth[2*L_CODES+1]; + // Depth of each subtree used as tie breaker for trees of equal frequency + + uch length_code[MAX_MATCH-MIN_MATCH+1]; + // length code for each normalized match length (0 == MIN_MATCH) + + uch dist_code[512]; + // distance codes. The first 256 values correspond to the distances + // 3 .. 258, the last 256 values correspond to the top 8 bits of + // the 15 bit distances. + + int base_length[LENGTH_CODES]; + // First normalized length for each code (0 = MIN_MATCH) + + int base_dist[D_CODES]; + // First normalized distance for each code (0 = distance of 1) + + uch l_buf[LIT_BUFSIZE]; // buffer for literals/lengths + ush d_buf[DIST_BUFSIZE]; // buffer for distances + + uch flag_buf[(LIT_BUFSIZE/8)]; + // flag_buf is a bit array distinguishing literals from lengths in + // l_buf, and thus indicating the presence or absence of a distance. + + unsigned last_lit; // running index in l_buf + unsigned last_dist; // running index in d_buf + unsigned last_flags; // running index in flag_buf + uch flags; // current flags not yet saved in flag_buf + uch flag_bit; // current bit used in flags + // bits are filled in flags starting at bit 0 (least significant). + // Note: these flags are overkill in the current code since we don't + // take advantage of DIST_BUFSIZE == LIT_BUFSIZE. + + ulg opt_len; // bit length of current block with optimal trees + ulg static_len; // bit length of current block with static trees + + ulg cmpr_bytelen; // total byte length of compressed file + ulg cmpr_len_bits; // number of bits past 'cmpr_bytelen' + + ulg input_len; // total byte length of input file + // input_len is for debugging only since we can get it by other means. + + ush *file_type; // pointer to UNKNOWN, BINARY or ASCII +// int *file_method; // pointer to DEFLATE or STORE +}; + +TTreeState::TTreeState() +{ tree_desc a = {dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0}; l_desc = a; + tree_desc b = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; d_desc = b; + tree_desc c = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; bl_desc = c; + last_lit=0; + last_dist=0; + last_flags=0; +} + + + +class TBitState +{ public: + + int flush_flg; + // + unsigned bi_buf; + // Output buffer. bits are inserted starting at the bottom (least significant + // bits). The width of bi_buf must be at least 16 bits. + int bi_valid; + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + char *out_buf; + // Current output buffer. + unsigned out_offset; + // Current offset in output buffer. + // On 16 bit machines, the buffer is limited to 64K. + unsigned out_size; + // Size of current output buffer + ulg bits_sent; // bit length of the compressed data only needed for debugging??? +}; + + + + + + + +class TDeflateState +{ public: + TDeflateState() {window_size=0;} + + uch window[2L*WSIZE]; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least WSIZE + // bytes. With this organization, matches are limited to a distance of + // WSIZE-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would + // be less efficient since the data would have to be copied WSIZE/CBSZ times) + Pos prev[WSIZE]; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + Pos head[HASH_SIZE]; + // Heads of the hash chains or NIL. If your compiler thinks that + // HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC. + + ulg window_size; + // window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the + // input file length plus MIN_LOOKAHEAD. + + long block_start; + // window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + int sliding; + // Set to false when the input file is already in memory + + unsigned ins_h; // hash index of string to be inserted + + unsigned int prev_length; + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + + unsigned strstart; // start of string to insert + unsigned match_start; // start of matching string + int eofile; // flag set at end of input file + unsigned lookahead; // number of valid bytes ahead in window + + unsigned max_chain_length; + // To speed up deflation, hash chains are never searched beyond this length. + // A higher limit improves compression ratio but degrades the speed. + + unsigned int max_lazy_match; + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + + unsigned good_match; + // Use a faster search when the previous match is longer than this + + int nice_match; // Stop searching when current match exceeds this +}; + +typedef long lutime_t; // define it ourselves since we don't include time.h + +typedef struct iztimes { + lutime_t atime,mtime,ctime; +} iztimes; // access, modify, create times + +typedef struct zlist { + ush vem, ver, flg, how; // See central header in zipfile.c for what vem..off are + ulg tim, crc, siz, len; + extent nam, ext, cext, com; // offset of ext must be >= LOCHEAD + ush dsk, att, lflg; // offset of lflg must be >= LOCHEAD + ulg atx, off; + char name[MAX_PATH]; // File name in zip file + char *extra; // Extra field (set only if ext != 0) + char *cextra; // Extra in central (set only if cext != 0) + char *comment; // Comment (set only if com != 0) + char iname[MAX_PATH]; // Internal file name after cleanup + char zname[MAX_PATH]; // External version of internal name + int mark; // Marker for files to operate on + int trash; // Marker for files to delete + int dosflag; // Set to force MSDOS file attributes + struct zlist *nxt; // Pointer to next header in list +} TZipFileInfo; + + +struct TState; +typedef unsigned (*READFUNC)(TState &state, char *buf,unsigned size); +typedef unsigned (*FLUSHFUNC)(void *param, const char *buf, unsigned *size); +typedef unsigned (*WRITEFUNC)(void *param, const char *buf, unsigned size); +struct TState +{ void *param; + int level; bool seekable; + READFUNC readfunc; FLUSHFUNC flush_outbuf; + TTreeState ts; TBitState bs; TDeflateState ds; + const char *err; +}; + + + + +// ---------------------------------------------------------------------- +// some windows<->linux portability things +#ifdef ZIP_STD +void filetime2dosdatetime(const FILETIME ft, WORD *dosdate, WORD *dostime) +{ struct tm *st=gmtime(&ft); + *dosdate = (ush)(((st->tm_year+1900 -1980)&0x7f) << 9); + *dosdate |= (ush)((st->tm_mon&0xf) << 5); + *dosdate |= (ush)((st->tm_mday&0x1f)); + *dostime = (ush)((st->tm_hour&0x1f) << 11); + *dostime |= (ush)((st->tm_min&0x3f) << 5); + *dostime |= (ush)((st->tm_sec*2)&0x1f); +} + +void GetNow(lutime_t *ft, WORD *dosdate, WORD *dostime) +{ time_t tm = time(0); + filetime2dosdatetime(tm,dosdate,dostime); + *ft = (lutime_t)tm; +} + +DWORD GetFilePosZ(HANDLE hfout) +{ struct stat st; fstat(fileno(hfout),&st); + if ((st.st_mode&S_IFREG)==0) return 0xFFFFFFFF; + return ftell(hfout); +} + +ZRESULT GetFileInfo(FILE *hf, ulg *attr, long *size, iztimes *times, ulg *timestamp) +{ // The handle must be a handle to a file + // The date and time is returned in a long with the date most significant to allow + // unsigned integer comparison of absolute times. The attributes have two + // high bytes unix attr, and two low bytes a mapping of that to DOS attr. + struct stat bhi; int res=fstat(fileno(hf),&bhi); if (res==-1) return ZR_NOFILE; + ulg fa=bhi.st_mode; ulg a=0; + // Zip uses the lower word for its interpretation of windows stuff + if ((fa&S_IWUSR)==0) a|=0x01; + if (S_ISDIR(fa)) a|=0x10; + // It uses the upper word for standard unix attr + a |= ((fa&0xFFFF)<<16); + // + if (attr!=NULL) *attr = a; + if (size!=NULL) *size = bhi.st_size; + if (times!=NULL) + { times->atime = (lutime_t)bhi.st_atime; + times->mtime = (lutime_t)bhi.st_mtime; + times->ctime = (lutime_t)bhi.st_ctime; + } + if (timestamp!=NULL) + { ush dosdate,dostime; + filetime2dosdatetime(bhi.st_mtime,&dosdate,&dostime); + *timestamp = (ush)dostime | (((ulg)dosdate)<<16); + } + return ZR_OK; +} + + +// ---------------------------------------------------------------------- +#else +void filetime2dosdatetime(const FILETIME ft, WORD *dosdate,WORD *dostime) +{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980 + // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23 + SYSTEMTIME st; FileTimeToSystemTime(&ft,&st); + *dosdate = (WORD)(((st.wYear-1980)&0x7f) << 9); + *dosdate |= (WORD)((st.wMonth&0xf) << 5); + *dosdate |= (WORD)((st.wDay&0x1f)); + *dostime = (WORD)((st.wHour&0x1f) << 11); + *dostime |= (WORD)((st.wMinute&0x3f) << 5); + *dostime |= (WORD)((st.wSecond*2)&0x1f); +} + +lutime_t filetime2timet(const FILETIME ft) +{ LONGLONG i = *(LONGLONG*)&ft; + return (lutime_t)((i-116444736000000000LL)/10000000LL); +} + +void GetNow(lutime_t *pft, WORD *dosdate, WORD *dostime) +{ SYSTEMTIME st; GetLocalTime(&st); + FILETIME ft; SystemTimeToFileTime(&st,&ft); + filetime2dosdatetime(ft,dosdate,dostime); + *pft = filetime2timet(ft); +} + +DWORD GetFilePosZ(HANDLE hfout) +{ return SetFilePointer(hfout,0,0,FILE_CURRENT); +} + + +ZRESULT GetFileInfo(HANDLE hf, ulg *attr, long *size, iztimes *times, ulg *timestamp) +{ // The handle must be a handle to a file + // The date and time is returned in a long with the date most significant to allow + // unsigned integer comparison of absolute times. The attributes have two + // high bytes unix attr, and two low bytes a mapping of that to DOS attr. + //struct stat s; int res=stat(fn,&s); if (res!=0) return false; + // translate windows file attributes into zip ones. + BY_HANDLE_FILE_INFORMATION bhi; BOOL res=GetFileInformationByHandle(hf,&bhi); + if (!res) return ZR_NOFILE; + DWORD fa=bhi.dwFileAttributes; ulg a=0; + // Zip uses the lower word for its interpretation of windows stuff + if (fa&FILE_ATTRIBUTE_READONLY) a|=0x01; + if (fa&FILE_ATTRIBUTE_HIDDEN) a|=0x02; + if (fa&FILE_ATTRIBUTE_SYSTEM) a|=0x04; + if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x10; + if (fa&FILE_ATTRIBUTE_ARCHIVE) a|=0x20; + // It uses the upper word for standard unix attr, which we manually construct + if (fa&FILE_ATTRIBUTE_DIRECTORY)a|=0x40000000; // directory + else a|=0x80000000; // normal file + a|=0x01000000; // readable + if (fa&FILE_ATTRIBUTE_READONLY) {} else a|=0x00800000; // writeable + // now just a small heuristic to check if it's an executable: + DWORD red, hsize=GetFileSize(hf,NULL); if (hsize>40) + { SetFilePointer(hf,0,NULL,FILE_BEGIN); unsigned short magic; ReadFile(hf,&magic,sizeof(magic),&red,NULL); + SetFilePointer(hf,36,NULL,FILE_BEGIN); unsigned long hpos; ReadFile(hf,&hpos,sizeof(hpos),&red,NULL); + if (magic==0x54AD && hsize>hpos+4+20+28) + { SetFilePointer(hf,hpos,NULL,FILE_BEGIN); unsigned long signature; ReadFile(hf,&signature,sizeof(signature),&red,NULL); + if (signature==IMAGE_DOS_SIGNATURE || signature==IMAGE_OS2_SIGNATURE + || signature==IMAGE_OS2_SIGNATURE_LE || signature==IMAGE_NT_SIGNATURE) + { a |= 0x00400000; // executable + } + } + } + // + if (attr!=NULL) *attr = a; + if (size!=NULL) *size = hsize; + if (times!=NULL) + { // lutime_t is 32bit number of seconds elapsed since 0:0:0GMT, Jan1, 1970. + // but FILETIME is 64bit number of 100-nanosecs since Jan1, 1601 + times->atime = filetime2timet(bhi.ftLastAccessTime); + times->mtime = filetime2timet(bhi.ftLastWriteTime); + times->ctime = filetime2timet(bhi.ftCreationTime); + } + if (timestamp!=NULL) + { WORD dosdate,dostime; + filetime2dosdatetime(bhi.ftLastWriteTime,&dosdate,&dostime); + *timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + } + return ZR_OK; +} +#endif +// ---------------------------------------------------------------------- + + + + + +void Assert(TState &state,bool cond, const char *msg) +{ if (cond) return; + state.err=msg; +} +void Trace(const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} +void Tracec(bool ,const char *x, ...) {va_list paramList; va_start(paramList, x); paramList; va_end(paramList);} + + + +// =========================================================================== +// Local (static) routines in this file. +// + +void init_block (TState &); +void pqdownheap (TState &,ct_data *tree, int k); +void gen_bitlen (TState &,tree_desc *desc); +void gen_codes (TState &state,ct_data *tree, int max_code); +void build_tree (TState &,tree_desc *desc); +void scan_tree (TState &,ct_data *tree, int max_code); +void send_tree (TState &state,ct_data *tree, int max_code); +int build_bl_tree (TState &); +void send_all_trees (TState &state,int lcodes, int dcodes, int blcodes); +void compress_block (TState &state,ct_data *ltree, ct_data *dtree); +void set_file_type (TState &); +void send_bits (TState &state, int value, int length); +unsigned bi_reverse (unsigned code, int len); +void bi_windup (TState &state); +void copy_block (TState &state,char *buf, unsigned len, int header); + + +#define send_code(state, c, tree) send_bits(state, tree[c].fc.code, tree[c].dl.len) +// Send a code of the given tree. c and tree must not have side effects + +// alternatively... +//#define send_code(state, c, tree) +// { if (state.verbose>1) fprintf(stderr,"\ncd %3d ",(c)); +// send_bits(state, tree[c].fc.code, tree[c].dl.len); } + +#define d_code(dist) ((dist) < 256 ? state.ts.dist_code[dist] : state.ts.dist_code[256+((dist)>>7)]) +// Mapping from a distance to a distance code. dist is the distance - 1 and +// must not have side effects. dist_code[256] and dist_code[257] are never used. + +#define Max(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Allocate the match buffer, initialize the various tables and save the + * location of the internal file attribute (ascii/binary) and method + * (DEFLATE/STORE). + */ +void ct_init(TState &state, ush *attr) +{ + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + + state.ts.file_type = attr; + //state.ts.file_method = method; + state.ts.cmpr_bytelen = state.ts.cmpr_len_bits = 0L; + state.ts.input_len = 0L; + + if (state.ts.static_dtree[0].dl.len != 0) return; /* ct_init already called */ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + state.ts.base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + state.ts.base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + state.ts.base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + state.ts.dist_code[256 + dist++] = (uch)code; + } + } + Assert(state,dist == 256, "ct_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; + n = 0; + while (n <= 143) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; + while (n <= 255) state.ts.static_ltree[n++].dl.len = 9, state.ts.bl_count[9]++; + while (n <= 279) state.ts.static_ltree[n++].dl.len = 7, state.ts.bl_count[7]++; + while (n <= 287) state.ts.static_ltree[n++].dl.len = 8, state.ts.bl_count[8]++; + /* fc.codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(state,(ct_data *)state.ts.static_ltree, L_CODES+1); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + state.ts.static_dtree[n].dl.len = 5; + state.ts.static_dtree[n].fc.code = (ush)bi_reverse(n, 5); + } + + /* Initialize the first block of the first file: */ + init_block(state); +} + +/* =========================================================================== + * Initialize a new block. + */ +void init_block(TState &state) +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) state.ts.dyn_ltree[n].fc.freq = 0; + for (n = 0; n < D_CODES; n++) state.ts.dyn_dtree[n].fc.freq = 0; + for (n = 0; n < BL_CODES; n++) state.ts.bl_tree[n].fc.freq = 0; + + state.ts.dyn_ltree[END_BLOCK].fc.freq = 1; + state.ts.opt_len = state.ts.static_len = 0L; + state.ts.last_lit = state.ts.last_dist = state.ts.last_flags = 0; + state.ts.flags = 0; state.ts.flag_bit = 1; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(tree, top) \ +{\ + top = state.ts.heap[SMALLEST]; \ + state.ts.heap[SMALLEST] = state.ts.heap[state.ts.heap_len--]; \ + pqdownheap(state,tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m) \ + (tree[n].fc.freq < tree[m].fc.freq || \ + (tree[n].fc.freq == tree[m].fc.freq && state.ts.depth[n] <= state.ts.depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +void pqdownheap(TState &state,ct_data *tree, int k) +{ + int v = state.ts.heap[k]; + int j = k << 1; /* left son of k */ + int htemp; /* required because of bug in SASC compiler */ + + while (j <= state.ts.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < state.ts.heap_len && smaller(tree, state.ts.heap[j+1], state.ts.heap[j])) j++; + + /* Exit if v is smaller than both sons */ + htemp = state.ts.heap[j]; + if (smaller(tree, v, htemp)) break; + + /* Exchange v with the smallest son */ + state.ts.heap[k] = htemp; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + state.ts.heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +void gen_bitlen(TState &state,tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + const int *extra = desc->extra_bits; + int base = desc->extra_base; + int max_code = desc->max_code; + int max_length = desc->max_length; + ct_data *stree = desc->static_tree; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) state.ts.bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[state.ts.heap[state.ts.heap_max]].dl.len = 0; /* root of the heap */ + + for (h = state.ts.heap_max+1; h < HEAP_SIZE; h++) { + n = state.ts.heap[h]; + bits = tree[tree[n].dl.dad].dl.len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].dl.len = (ush)bits; + /* We overwrite tree[n].dl.dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + state.ts.bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].fc.freq; + state.ts.opt_len += (ulg)f * (bits + xbits); + if (stree) state.ts.static_len += (ulg)f * (stree[n].dl.len + xbits); + } + if (overflow == 0) return; + + Trace("\nbit length overflow\n"); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (state.ts.bl_count[bits] == 0) bits--; + state.ts.bl_count[bits]--; /* move one leaf down the tree */ + state.ts.bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */ + state.ts.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = state.ts.bl_count[bits]; + while (n != 0) { + m = state.ts.heap[--h]; + if (m > max_code) continue; + if (tree[m].dl.len != (ush)bits) { + Trace("code %d bits %d->%d\n", m, tree[m].dl.len, bits); + state.ts.opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; + tree[m].dl.len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +void gen_codes (TState &state, ct_data *tree, int max_code) +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (ush)((code + state.ts.bl_count[bits-1]) << 1); + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert(state,code + state.ts.bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1, + "inconsistent bit counts"); + Trace("\ngen_codes: max_code %d ", max_code); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].dl.len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].fc.code = (ush)bi_reverse(next_code[len]++, len); + + //Tracec(tree != state.ts.static_ltree, "\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].fc.code, next_code[len]-1); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +void build_tree(TState &state,tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + ct_data *stree = desc->static_tree; + int elems = desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node = elems; /* next internal node of the tree */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + state.ts.heap_len = 0, state.ts.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].fc.freq != 0) { + state.ts.heap[++state.ts.heap_len] = max_code = n; + state.ts.depth[n] = 0; + } else { + tree[n].dl.len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (state.ts.heap_len < 2) { + int newcp = state.ts.heap[++state.ts.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[newcp].fc.freq = 1; + state.ts.depth[newcp] = 0; + state.ts.opt_len--; if (stree) state.ts.static_len -= stree[newcp].dl.len; + /* new is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = state.ts.heap_len/2; n >= 1; n--) pqdownheap(state,tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do { + pqremove(tree, n); /* n = node of least frequency */ + m = state.ts.heap[SMALLEST]; /* m = node of next least frequency */ + + state.ts.heap[--state.ts.heap_max] = n; /* keep the nodes sorted by frequency */ + state.ts.heap[--state.ts.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node].fc.freq = (ush)(tree[n].fc.freq + tree[m].fc.freq); + state.ts.depth[node] = (uch) (Max(state.ts.depth[n], state.ts.depth[m]) + 1); + tree[n].dl.dad = tree[m].dl.dad = (ush)node; + /* and insert the new node in the heap */ + state.ts.heap[SMALLEST] = node++; + pqdownheap(state,tree, SMALLEST); + + } while (state.ts.heap_len >= 2); + + state.ts.heap[--state.ts.heap_max] = state.ts.heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(state,(tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes (state,(ct_data *)tree, max_code); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. Updates opt_len to take into account the repeat + * counts. (The contribution of the bit length codes will be added later + * during the construction of bl_tree.) + */ +void scan_tree (TState &state,ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].dl.len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].dl.len = (ush)-1; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].dl.len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + state.ts.bl_tree[curlen].fc.freq = (ush)(state.ts.bl_tree[curlen].fc.freq + count); + } else if (curlen != 0) { + if (curlen != prevlen) state.ts.bl_tree[curlen].fc.freq++; + state.ts.bl_tree[REP_3_6].fc.freq++; + } else if (count <= 10) { + state.ts.bl_tree[REPZ_3_10].fc.freq++; + } else { + state.ts.bl_tree[REPZ_11_138].fc.freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +void send_tree (TState &state, ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].dl.len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].dl.len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].dl.len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(state, curlen, state.ts.bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(state, curlen, state.ts.bl_tree); count--; + } + Assert(state,count >= 3 && count <= 6, " 3_6?"); + send_code(state,REP_3_6, state.ts.bl_tree); send_bits(state,count-3, 2); + + } else if (count <= 10) { + send_code(state,REPZ_3_10, state.ts.bl_tree); send_bits(state,count-3, 3); + + } else { + send_code(state,REPZ_11_138, state.ts.bl_tree); send_bits(state,count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +int build_bl_tree(TState &state) +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(state,(ct_data *)state.ts.dyn_ltree, state.ts.l_desc.max_code); + scan_tree(state,(ct_data *)state.ts.dyn_dtree, state.ts.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(state,(tree_desc *)(&state.ts.bl_desc)); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (state.ts.bl_tree[bl_order[max_blindex]].dl.len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + state.ts.opt_len += 3*(max_blindex+1) + 5+5+4; + Trace("\ndyn trees: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +void send_all_trees(TState &state,int lcodes, int dcodes, int blcodes) +{ + int rank; /* index in bl_order */ + + Assert(state,lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert(state,lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Trace("\nbl counts: "); + send_bits(state,lcodes-257, 5); + /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */ + send_bits(state,dcodes-1, 5); + send_bits(state,blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Trace("\nbl code %2d ", bl_order[rank]); + send_bits(state,state.ts.bl_tree[bl_order[rank]].dl.len, 3); + } + Trace("\nbl tree: sent %ld", state.bs.bits_sent); + + send_tree(state,(ct_data *)state.ts.dyn_ltree, lcodes-1); /* send the literal tree */ + Trace("\nlit tree: sent %ld", state.bs.bits_sent); + + send_tree(state,(ct_data *)state.ts.dyn_dtree, dcodes-1); /* send the distance tree */ + Trace("\ndist tree: sent %ld", state.bs.bits_sent); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length (in bytes) for the file so far. + */ +ulg flush_block(TState &state,char *buf, ulg stored_len, int eof) +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex; /* index of last bit length code of non zero freq */ + + state.ts.flag_buf[state.ts.last_flags] = state.ts.flags; /* Save the flags for the last 8 items */ + + /* Check if the file is ascii or binary */ + if (*state.ts.file_type == (ush)UNKNOWN) set_file_type(state); + + /* Construct the literal and distance trees */ + build_tree(state,(tree_desc *)(&state.ts.l_desc)); + Trace("\nlit data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + + build_tree(state,(tree_desc *)(&state.ts.d_desc)); + Trace("\ndist data: dyn %ld, stat %ld", state.ts.opt_len, state.ts.static_len); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(state); + + /* Determine the best encoding. Compute first the block length in bytes */ + opt_lenb = (state.ts.opt_len+3+7)>>3; + static_lenb = (state.ts.static_len+3+7)>>3; + state.ts.input_len += stored_len; /* for debugging only */ + + Trace("\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + opt_lenb, state.ts.opt_len, static_lenb, state.ts.static_len, stored_len, + state.ts.last_lit, state.ts.last_dist); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + // Originally, zip allowed the file to be transformed from a compressed + // into a stored file in the case where compression failed, there + // was only one block, and it was allowed to change. I've removed this + // possibility since the code's cleaner if no changes are allowed. + //if (stored_len <= opt_lenb && eof && state.ts.cmpr_bytelen == 0L + // && state.ts.cmpr_len_bits == 0L && state.seekable) + //{ // && state.ts.file_method != NULL + // // Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: + // Assert(state,buf!=NULL,"block vanished"); + // copy_block(state,buf, (unsigned)stored_len, 0); // without header + // state.ts.cmpr_bytelen = stored_len; + // Assert(state,false,"unimplemented *state.ts.file_method = STORE;"); + // //*state.ts.file_method = STORE; + //} + //else + if (stored_len+4 <= opt_lenb && buf != (char*)NULL) { + /* 4: two words for the lengths */ + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + send_bits(state,(STORED_BLOCK<<1)+eof, 3); /* send block type */ + state.ts.cmpr_bytelen += ((state.ts.cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4; + state.ts.cmpr_len_bits = 0L; + + copy_block(state,buf, (unsigned)stored_len, 1); /* with header */ + } + else if (static_lenb == opt_lenb) { + send_bits(state,(STATIC_TREES<<1)+eof, 3); + compress_block(state,(ct_data *)state.ts.static_ltree, (ct_data *)state.ts.static_dtree); + state.ts.cmpr_len_bits += 3 + state.ts.static_len; + state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; + state.ts.cmpr_len_bits &= 7L; + } + else { + send_bits(state,(DYN_TREES<<1)+eof, 3); + send_all_trees(state,state.ts.l_desc.max_code+1, state.ts.d_desc.max_code+1, max_blindex+1); + compress_block(state,(ct_data *)state.ts.dyn_ltree, (ct_data *)state.ts.dyn_dtree); + state.ts.cmpr_len_bits += 3 + state.ts.opt_len; + state.ts.cmpr_bytelen += state.ts.cmpr_len_bits >> 3; + state.ts.cmpr_len_bits &= 7L; + } + Assert(state,((state.ts.cmpr_bytelen << 3) + state.ts.cmpr_len_bits) == state.bs.bits_sent, "bad compressed size"); + init_block(state); + + if (eof) { + // Assert(state,input_len == isize, "bad input size"); + bi_windup(state); + state.ts.cmpr_len_bits += 7; /* align on byte boundary */ + } + Trace("\n"); + + return state.ts.cmpr_bytelen + (state.ts.cmpr_len_bits >> 3); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ct_tally (TState &state,int dist, int lc) +{ + state.ts.l_buf[state.ts.last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + state.ts.dyn_ltree[lc].fc.freq++; + } else { + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert(state,(ush)dist < (ush)MAX_DIST && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match"); + + state.ts.dyn_ltree[state.ts.length_code[lc]+LITERALS+1].fc.freq++; + state.ts.dyn_dtree[d_code(dist)].fc.freq++; + + state.ts.d_buf[state.ts.last_dist++] = (ush)dist; + state.ts.flags |= state.ts.flag_bit; + } + state.ts.flag_bit <<= 1; + + /* Output the flags if they fill a byte: */ + if ((state.ts.last_lit & 7) == 0) { + state.ts.flag_buf[state.ts.last_flags++] = state.ts.flags; + state.ts.flags = 0, state.ts.flag_bit = 1; + } + /* Try to guess if it is profitable to stop the current block here */ + if (state.level > 2 && (state.ts.last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)state.ts.last_lit*8L; + ulg in_length = (ulg)state.ds.strstart-state.ds.block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)state.ts.dyn_dtree[dcode].fc.freq*(5L+extra_dbits[dcode]); + } + out_length >>= 3; + Trace("\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + state.ts.last_lit, state.ts.last_dist, in_length, out_length, + 100L - out_length*100L/in_length); + if (state.ts.last_dist < state.ts.last_lit/2 && out_length < in_length/2) return 1; + } + return (state.ts.last_lit == LIT_BUFSIZE-1 || state.ts.last_dist == DIST_BUFSIZE); + /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +void compress_block(TState &state,ct_data *ltree, ct_data *dtree) +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned dx = 0; /* running index in d_buf */ + unsigned fx = 0; /* running index in flag_buf */ + uch flag = 0; /* current flags */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (state.ts.last_lit != 0) do { + if ((lx & 7) == 0) flag = state.ts.flag_buf[fx++]; + lc = state.ts.l_buf[lx++]; + if ((flag & 1) == 0) { + send_code(state,lc, ltree); /* send a literal byte */ + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = state.ts.length_code[lc]; + send_code(state,code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= state.ts.base_length[code]; + send_bits(state,lc, extra); /* send the extra length bits */ + } + dist = state.ts.d_buf[dx++]; + /* Here, dist is the match distance - 1 */ + code = d_code(dist); + Assert(state,code < D_CODES, "bad d_code"); + + send_code(state,code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= state.ts.base_dist[code]; + send_bits(state,dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + flag >>= 1; + } while (lx < state.ts.last_lit); + + send_code(state,END_BLOCK, ltree); +} + +/* =========================================================================== + * Set the file type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +void set_file_type(TState &state) +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += state.ts.dyn_ltree[n++].fc.freq; + while (n < 128) ascii_freq += state.ts.dyn_ltree[n++].fc.freq; + while (n < LITERALS) bin_freq += state.ts.dyn_ltree[n++].fc.freq; + *state.ts.file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); +} + + +/* =========================================================================== + * Initialize the bit string routines. + */ +void bi_init (TState &state,char *tgt_buf, unsigned tgt_size, int flsh_allowed) +{ + state.bs.out_buf = tgt_buf; + state.bs.out_size = tgt_size; + state.bs.out_offset = 0; + state.bs.flush_flg = flsh_allowed; + + state.bs.bi_buf = 0; + state.bs.bi_valid = 0; + state.bs.bits_sent = 0L; +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +void send_bits(TState &state,int value, int length) +{ + Assert(state,length > 0 && length <= 15, "invalid length"); + state.bs.bits_sent += (ulg)length; + /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and + * (Buf_size - bi_valid) bits from value to flush the filled bi_buf, + * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid)) + * unused bits in bi_buf. + */ + state.bs.bi_buf |= (value << state.bs.bi_valid); + state.bs.bi_valid += length; + if (state.bs.bi_valid > (int)Buf_size) { + PUTSHORT(state,state.bs.bi_buf); + state.bs.bi_valid -= Buf_size; + state.bs.bi_buf = (unsigned)value >> (length - state.bs.bi_valid); + } +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +unsigned bi_reverse(unsigned code, int len) +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Write out any remaining bits in an incomplete byte. + */ +void bi_windup(TState &state) +{ + if (state.bs.bi_valid > 8) { + PUTSHORT(state,state.bs.bi_buf); + } else if (state.bs.bi_valid > 0) { + PUTBYTE(state,state.bs.bi_buf); + } + if (state.bs.flush_flg) { + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); + } + state.bs.bi_buf = 0; + state.bs.bi_valid = 0; + state.bs.bits_sent = (state.bs.bits_sent+7) & ~7; +} + +/* =========================================================================== + * Copy a stored block to the zip file, storing first the length and its + * one's complement if requested. + */ +void copy_block(TState &state, char *block, unsigned len, int header) +{ + bi_windup(state); /* align on byte boundary */ + + if (header) { + PUTSHORT(state,(ush)len); + PUTSHORT(state,(ush)~len); + state.bs.bits_sent += 2*16; + } + if (state.bs.flush_flg) { + state.flush_outbuf(state.param,state.bs.out_buf, &state.bs.out_offset); + state.bs.out_offset = len; + state.flush_outbuf(state.param,block, &state.bs.out_offset); + } else if (state.bs.out_offset + len > state.bs.out_size) { + Assert(state,false,"output buffer too small for in-memory compression"); + } else { + memcpy(state.bs.out_buf + state.bs.out_offset, block, len); + state.bs.out_offset += len; + } + state.bs.bits_sent += (ulg)len<<3; +} + + + + + + + + +/* =========================================================================== + * Prototypes for functions. + */ + +void fill_window (TState &state); +ulg deflate_fast (TState &state); + +int longest_match (TState &state,IPos cur_match); + + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(h,c) (h = (((h)< 0 if the input file is already read or + * mmap'ed in the window[] array, 0 otherwise. In the first case, + * window_size is sufficient to contain the whole input file plus + * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end + * of window[] when looking for matches towards the end). + */ +void lm_init (TState &state, int pack_level, ush *flags) +{ + register unsigned j; + + Assert(state,pack_level>=1 && pack_level<=8,"bad pack level"); + + /* Do not slide the window if the whole input is already in memory + * (window_size > 0) + */ + state.ds.sliding = 0; + if (state.ds.window_size == 0L) { + state.ds.sliding = 1; + state.ds.window_size = (ulg)2L*WSIZE; + } + + /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ + state.ds.head[HASH_SIZE-1] = NIL; + memset((char*)state.ds.head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*state.ds.head)); + + /* Set the default configuration parameters: + */ + state.ds.max_lazy_match = configuration_table[pack_level].max_lazy; + state.ds.good_match = configuration_table[pack_level].good_length; + state.ds.nice_match = configuration_table[pack_level].nice_length; + state.ds.max_chain_length = configuration_table[pack_level].max_chain; + if (pack_level <= 2) { + *flags |= FAST; + } else if (pack_level >= 8) { + *flags |= SLOW; + } + /* ??? reduce max_chain_length for binary files */ + + state.ds.strstart = 0; + state.ds.block_start = 0L; + + j = WSIZE; + j <<= 1; // Can read 64K in one step + state.ds.lookahead = state.readfunc(state, (char*)state.ds.window, j); + + if (state.ds.lookahead == 0 || state.ds.lookahead == (unsigned)EOF) { + state.ds.eofile = 1, state.ds.lookahead = 0; + return; + } + state.ds.eofile = 0; + /* Make sure that we always have enough lookahead. This is important + * if input comes from a device such as a tty. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + + state.ds.ins_h = 0; + for (j=0; j= 1 + */ +// For 80x86 and 680x0 and ARM, an optimized version is in match.asm or +// match.S. The code is functionally equivalent, so you can use the C version +// if desired. Which I do so desire! +int longest_match(TState &state,IPos cur_match) +{ + unsigned chain_length = state.ds.max_chain_length; /* max hash chain length */ + register uch *scan = state.ds.window + state.ds.strstart; /* current string */ + register uch *match; /* matched string */ + register int len; /* length of current match */ + int best_len = state.ds.prev_length; /* best match length so far */ + IPos limit = state.ds.strstart > (IPos)MAX_DIST ? state.ds.strstart - (IPos)MAX_DIST : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + Assert(state,HASH_BITS>=8 && MAX_MATCH==258,"Code too clever"); + + + + register uch *strend = state.ds.window + state.ds.strstart + MAX_MATCH; + register uch scan_end1 = scan[best_len-1]; + register uch scan_end = scan[best_len]; + + /* Do not waste too much time if we already have a good match: */ + if (state.ds.prev_length >= state.ds.good_match) { + chain_length >>= 2; + } + + Assert(state,state.ds.strstart <= state.ds.window_size-MIN_LOOKAHEAD, "insufficient lookahead"); + + do { + Assert(state,cur_match < state.ds.strstart, "no future"); + match = state.ds.window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(state,scan <= state.ds.window+(unsigned)(state.ds.window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + + if (len > best_len) { + state.ds.match_start = cur_match; + best_len = len; + if (len >= state.ds.nice_match) break; + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; + } + } while ((cur_match = state.ds.prev[cur_match & WMASK]) > limit + && --chain_length != 0); + + return best_len; +} + + + +#define check_match(state,start, match, length) +// or alternatively... +//void check_match(TState &state,IPos start, IPos match, int length) +//{ // check that the match is indeed a match +// if (memcmp((char*)state.ds.window + match, +// (char*)state.ds.window + start, length) != EQUAL) { +// fprintf(stderr, +// " start %d, match %d, length %d\n", +// start, match, length); +// error("invalid match"); +// } +// if (state.verbose > 1) { +// fprintf(stderr,"\\[%d,%d]", start-match, length); +// do { fprintf(stdout,"%c",state.ds.window[start++]); } while (--length != 0); +// } +//} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead, and sets eofile if end of input file. + * + * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or eofile is set; file reads are + * performed for at least two bytes (required for the translate_eol option). + */ +void fill_window(TState &state) +{ + register unsigned n, m; + unsigned more; /* Amount of free space at the end of the window. */ + + do { + more = (unsigned)(state.ds.window_size - (ulg)state.ds.lookahead - (ulg)state.ds.strstart); + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (more == (unsigned)EOF) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* For MMAP or BIG_MEM, the whole input file is already in memory so + * we must not perform sliding. We must however call (*read_buf)() in + * order to compute the crc, update lookahead and possibly set eofile. + */ + } else if (state.ds.strstart >= WSIZE+MAX_DIST && state.ds.sliding) { + + /* By the IN assertion, the window is not empty so we can't confuse + * more == 0 with more == 64K on a 16 bit machine. + */ + memcpy((char*)state.ds.window, (char*)state.ds.window+WSIZE, (unsigned)WSIZE); + state.ds.match_start -= WSIZE; + state.ds.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ + + state.ds.block_start -= (long) WSIZE; + + for (n = 0; n < HASH_SIZE; n++) { + m = state.ds.head[n]; + state.ds.head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); + } + for (n = 0; n < WSIZE; n++) { + m = state.ds.prev[n]; + state.ds.prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } + more += WSIZE; + } + if (state.ds.eofile) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the MMAP or BIG_MEM case (not yet supported in gzip), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(state,more >= 2, "more < 2"); + + n = state.readfunc(state, (char*)state.ds.window+state.ds.strstart+state.ds.lookahead, more); + + if (n == 0 || n == (unsigned)EOF) { + state.ds.eofile = 1; + } else { + state.ds.lookahead += n; + } + } while (state.ds.lookahead < MIN_LOOKAHEAD && !state.ds.eofile); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK(state,eof) \ + flush_block(state,state.ds.block_start >= 0L ? (char*)&state.ds.window[(unsigned)state.ds.block_start] : \ + (char*)NULL, (long)state.ds.strstart - state.ds.block_start, (eof)) + +/* =========================================================================== + * Processes a new input file and return its compressed length. This + * function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +ulg deflate_fast(TState &state) +{ + IPos hash_head = NIL; /* head of the hash chain */ + int flush; /* set if current block must be flushed */ + unsigned match_length = 0; /* length of best match */ + + state.ds.prev_length = MIN_MATCH-1; + while (state.ds.lookahead != 0) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (state.ds.lookahead >= MIN_MATCH) + INSERT_STRING(state.ds.strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && state.ds.strstart - hash_head <= MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + /* Do not look for matches beyond the end of the input. + * This is necessary to make deflate deterministic. + */ + if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; + match_length = longest_match (state,hash_head); + /* longest_match() sets match_start */ + if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; + } + if (match_length >= MIN_MATCH) { + check_match(state,state.ds.strstart, state.ds.match_start, match_length); + + flush = ct_tally(state,state.ds.strstart-state.ds.match_start, match_length - MIN_MATCH); + + state.ds.lookahead -= match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (match_length <= state.ds.max_insert_length + && state.ds.lookahead >= MIN_MATCH) { + match_length--; /* string at strstart already in hash table */ + do { + state.ds.strstart++; + INSERT_STRING(state.ds.strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--match_length != 0); + state.ds.strstart++; + } else { + state.ds.strstart += match_length; + match_length = 0; + state.ds.ins_h = state.ds.window[state.ds.strstart]; + UPDATE_HASH(state.ds.ins_h, state.ds.window[state.ds.strstart+1]); + Assert(state,MIN_MATCH==3,"Call UPDATE_HASH() MIN_MATCH-3 more times"); + } + } else { + /* No match, output a literal byte */ + flush = ct_tally (state,0, state.ds.window[state.ds.strstart]); + state.ds.lookahead--; + state.ds.strstart++; + } + if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + } + return FLUSH_BLOCK(state,1); /* eof */ +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +ulg deflate(TState &state) +{ + IPos hash_head = NIL; /* head of hash chain */ + IPos prev_match; /* previous match */ + int flush; /* set if current block must be flushed */ + int match_available = 0; /* set if previous match exists */ + register unsigned match_length = MIN_MATCH-1; /* length of best match */ + + if (state.level <= 3) return deflate_fast(state); /* optimized for speed */ + + /* Process the input block. */ + while (state.ds.lookahead != 0) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (state.ds.lookahead >= MIN_MATCH) + INSERT_STRING(state.ds.strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + */ + state.ds.prev_length = match_length, prev_match = state.ds.match_start; + match_length = MIN_MATCH-1; + + if (hash_head != NIL && state.ds.prev_length < state.ds.max_lazy_match && + state.ds.strstart - hash_head <= MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + /* Do not look for matches beyond the end of the input. + * This is necessary to make deflate deterministic. + */ + if ((unsigned)state.ds.nice_match > state.ds.lookahead) state.ds.nice_match = (int)state.ds.lookahead; + match_length = longest_match (state,hash_head); + /* longest_match() sets match_start */ + if (match_length > state.ds.lookahead) match_length = state.ds.lookahead; + + /* Ignore a length 3 match if it is too distant: */ + if (match_length == MIN_MATCH && state.ds.strstart-state.ds.match_start > TOO_FAR){ + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (state.ds.prev_length >= MIN_MATCH && match_length <= state.ds.prev_length) { + unsigned max_insert = state.ds.strstart + state.ds.lookahead - MIN_MATCH; + check_match(state,state.ds.strstart-1, prev_match, state.ds.prev_length); + flush = ct_tally(state,state.ds.strstart-1-prev_match, state.ds.prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. + */ + state.ds.lookahead -= state.ds.prev_length-1; + state.ds.prev_length -= 2; + do { + if (++state.ds.strstart <= max_insert) { + INSERT_STRING(state.ds.strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } + } while (--state.ds.prev_length != 0); + state.ds.strstart++; + match_available = 0; + match_length = MIN_MATCH-1; + + if (flush) FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + + } else if (match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + if (ct_tally (state,0, state.ds.window[state.ds.strstart-1])) { + FLUSH_BLOCK(state,0), state.ds.block_start = state.ds.strstart; + } + state.ds.strstart++; + state.ds.lookahead--; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + match_available = 1; + state.ds.strstart++; + state.ds.lookahead--; + } +// Assert(state,strstart <= isize && lookahead <= isize, "a bit too far"); + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (state.ds.lookahead < MIN_LOOKAHEAD) fill_window(state); + } + if (match_available) ct_tally (state,0, state.ds.window[state.ds.strstart-1]); + + return FLUSH_BLOCK(state,1); /* eof */ +} + + + + + + + + + + + + +int putlocal(struct zlist *z, WRITEFUNC wfunc,void *param) +{ // Write a local header described by *z to file *f. Return a ZE_ error code. + PUTLG(LOCSIG, f); + PUTSH(z->ver, f); + PUTSH(z->lflg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->ext, f); + size_t res = (size_t)wfunc(param, z->iname, (unsigned int)z->nam); + if (res!=z->nam) return ZE_TEMP; + if (z->ext) + { res = (size_t)wfunc(param, z->extra, (unsigned int)z->ext); + if (res!=z->ext) return ZE_TEMP; + } + return ZE_OK; +} + +int putextended(struct zlist *z, WRITEFUNC wfunc, void *param) +{ // Write an extended local header described by *z to file *f. Returns a ZE_ code + PUTLG(EXTLOCSIG, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + return ZE_OK; +} + +int putcentral(struct zlist *z, WRITEFUNC wfunc, void *param) +{ // Write a central header entry of *z to file *f. Returns a ZE_ code. + PUTLG(CENSIG, f); + PUTSH(z->vem, f); + PUTSH(z->ver, f); + PUTSH(z->flg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->cext, f); + PUTSH(z->com, f); + PUTSH(z->dsk, f); + PUTSH(z->att, f); + PUTLG(z->atx, f); + PUTLG(z->off, f); + if ((size_t)wfunc(param, z->iname, (unsigned int)z->nam) != z->nam || + (z->cext && (size_t)wfunc(param, z->cextra, (unsigned int)z->cext) != z->cext) || + (z->com && (size_t)wfunc(param, z->comment, (unsigned int)z->com) != z->com)) + return ZE_TEMP; + return ZE_OK; +} + + +int putend(int n, ulg s, ulg c, extent m, char *z, WRITEFUNC wfunc, void *param) +{ // write the end of the central-directory-data to file *f. + PUTLG(ENDSIG, f); + PUTSH(0, f); + PUTSH(0, f); + PUTSH(n, f); + PUTSH(n, f); + PUTLG(s, f); + PUTLG(c, f); + PUTSH(m, f); + // Write the comment, if any + if (m && wfunc(param, z, (unsigned int)m) != m) return ZE_TEMP; + return ZE_OK; +} + + + + + + +const ulg crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) +#define DO1(buf) crc = CRC32(crc, *buf++) +#define DO2(buf) DO1(buf); DO1(buf) +#define DO4(buf) DO2(buf); DO2(buf) +#define DO8(buf) DO4(buf); DO4(buf) + +ulg crc32(ulg crc, const uch *buf, extent len) +{ if (buf==NULL) return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) {DO8(buf); len -= 8;} + if (len) do {DO1(buf);} while (--len); + return crc ^ 0xffffffffL; // (instead of ~c for 64-bit machines) +} + + +void update_keys(unsigned long *keys, char c) +{ keys[0] = CRC32(keys[0],c); + keys[1] += keys[0] & 0xFF; + keys[1] = keys[1]*134775813L +1; + keys[2] = CRC32(keys[2], keys[1] >> 24); +} +char decrypt_byte(unsigned long *keys) +{ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2; + return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); +} +char zencode(unsigned long *keys, char c) +{ int t=decrypt_byte(keys); + update_keys(keys,c); + return (char)(t^c); +} + + + + + + + +int lustricmp(const TCHAR *sa, const TCHAR *sb) +{ for (const TCHAR *ca=sa, *cb=sb; ; ca++, cb++) + { int ia=tolower(*ca), ib=tolower(*cb); + if (ia==ib && ia==0) return 0; + if (ia==ib) continue; + if (iaib) return 1; + } +} + + +bool HasZipSuffix(const TCHAR *fn) +{ const TCHAR *ext = fn+_tcslen(fn); + while (ext>fn && *ext!='.') ext--; + if (ext==fn && *ext!='.') return false; + if (lustricmp(ext,_T(".Z"))==0) return true; + if (lustricmp(ext,_T(".zip"))==0) return true; + if (lustricmp(ext,_T(".zoo"))==0) return true; + if (lustricmp(ext,_T(".arc"))==0) return true; + if (lustricmp(ext,_T(".lzh"))==0) return true; + if (lustricmp(ext,_T(".arj"))==0) return true; + if (lustricmp(ext,_T(".gz"))==0) return true; + if (lustricmp(ext,_T(".tgz"))==0) return true; + return false; +} + + + + + + + + +class TZip +{ public: + TZip(const char *pwd) : hfout(0),mustclosehfout(false),hmapout(0),zfis(0),obuf(0),hfin(0),writ(0),oerr(false),hasputcen(false),ooffset(0),encwriting(false),encbuf(0),password(0), state(0) {if (pwd!=0 && *pwd!=0) {password=new char[strlen(pwd)+1]; strcpy(password,pwd);}} + ~TZip() {if (state!=0) delete state; state=0; if (encbuf!=0) delete[] encbuf; encbuf=0; if (password!=0) delete[] password; password=0;} + + // These variables say about the file we're writing into + // We can write to pipe, file-by-handle, file-by-name, memory-to-memmapfile + char *password; // keep a copy of the password + HANDLE hfout; // if valid, we'll write here (for files or pipes) + bool mustclosehfout; // if true, we are responsible for closing hfout + HANDLE hmapout; // otherwise, we'll write here (for memmap) + unsigned ooffset; // for hfout, this is where the pointer was initially + ZRESULT oerr; // did a write operation give rise to an error? + unsigned writ; // how far have we written. This is maintained by Add, not write(), to avoid confusion over seeks + bool ocanseek; // can we seek? + char *obuf; // this is where we've locked mmap to view. + unsigned int opos; // current pos in the mmap + unsigned int mapsize; // the size of the map we created + bool hasputcen; // have we yet placed the central directory? + bool encwriting; // if true, then we'll encrypt stuff using 'keys' before we write it to disk + unsigned long keys[3]; // keys are initialised inside Add() + char *encbuf; // if encrypting, then this is a temporary workspace for encrypting the data + unsigned int encbufsize; // (to be used and resized inside write(), and deleted in the destructor) + // + TZipFileInfo *zfis; // each file gets added onto this list, for writing the table at the end + TState *state; // we use just one state object per zip, because it's big (500k) + + ZRESULT Create(void *z,unsigned int len,DWORD flags); + static unsigned sflush(void *param,const char *buf, unsigned *size); + static unsigned swrite(void *param,const char *buf, unsigned size); + unsigned int write(const char *buf,unsigned int size); + bool oseek(unsigned int pos); + ZRESULT GetMemory(void **pbuf, unsigned long *plen); + ZRESULT Close(); + + // some variables to do with the file currently being read: + // I haven't done it object-orientedly here, just put them all + // together, since OO didn't seem to make the design any clearer. + ulg attr; iztimes times; ulg timestamp; // all open_* methods set these + bool iseekable; long isize,ired; // size is not set until close() on pips + ulg crc; // crc is not set until close(). iwrit is cumulative + HANDLE hfin; bool selfclosehf; // for input files and pipes + const char *bufin; unsigned int lenin,posin; // for memory + // and a variable for what we've done with the input: (i.e. compressed it!) + ulg csize; // compressed size, set by the compression routines + // and this is used by some of the compression routines + char buf[16384]; + + + ZRESULT open_file(const TCHAR *fn); + ZRESULT open_handle(HANDLE hf,unsigned int len); + ZRESULT open_mem(void *src,unsigned int len); + ZRESULT open_dir(); + static unsigned sread(TState &s,char *buf,unsigned size); + unsigned read(char *buf, unsigned size); + ZRESULT iclose(); + + ZRESULT ideflate(TZipFileInfo *zfi); + ZRESULT istore(); + + ZRESULT Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags); + ZRESULT AddCentral(); + +}; + + + +ZRESULT TZip::Create(void *z,unsigned int len,DWORD flags) +{ if (hfout!=0 || hmapout!=0 || obuf!=0 || writ!=0 || oerr!=ZR_OK || hasputcen) return ZR_NOTINITED; + // + if (flags==ZIP_HANDLE) + { HANDLE hf = (HANDLE)z; + hfout=hf; mustclosehfout=false; +#ifdef DuplicateHandle + BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&hfout,0,FALSE,DUPLICATE_SAME_ACCESS); + if (res) mustclosehandle=true; +#endif + // now we have hfout. Either we duplicated the handle and we close it ourselves + // (while the caller closes h themselves), or we couldn't duplicate it. + DWORD res=GetFilePosZ(hfout); + ocanseek = (res!=0xFFFFFFFF); + ooffset = ocanseek ? res : 0; + return ZR_OK; + } + else if (flags==ZIP_FILENAME) + { const TCHAR *fn = (const TCHAR*)z; +#ifdef ZIP_STD + hfout = fopen(fn,"wb"); + if (hfout==0) return ZR_NOFILE; +#else + hfout = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if (hfout==INVALID_HANDLE_VALUE) {hfout=0; return ZR_NOFILE;} +#endif + ocanseek=true; + ooffset=0; + mustclosehfout=true; + return ZR_OK; + } + else if (flags==ZIP_MEMORY) + { unsigned int size = len; + if (size==0) return ZR_MEMSIZE; +#ifdef ZIP_STD + if (z!=0) obuf=(char*)z; + else return ZR_ARGS; +#else + if (z!=0) obuf=(char*)z; + else + { hmapout = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,NULL); + if (hmapout==NULL) return ZR_NOALLOC; + obuf = (char*)MapViewOfFile(hmapout,FILE_MAP_ALL_ACCESS,0,0,size); + if (obuf==0) {CloseHandle(hmapout); hmapout=0; return ZR_NOALLOC;} + } +#endif + ocanseek=true; + opos=0; mapsize=size; + return ZR_OK; + } + else return ZR_ARGS; +} + +unsigned TZip::sflush(void *param,const char *buf, unsigned *size) +{ // static + if (*size==0) return 0; + TZip *zip = (TZip*)param; + unsigned int writ = zip->write(buf,*size); + if (writ!=0) *size=0; + return writ; +} +unsigned TZip::swrite(void *param,const char *buf, unsigned size) +{ // static + if (size==0) return 0; + TZip *zip=(TZip*)param; return zip->write(buf,size); +} +unsigned int TZip::write(const char *buf,unsigned int size) +{ const char *srcbuf=buf; + if (encwriting) + { if (encbuf!=0 && encbufsize=mapsize) {oerr=ZR_MEMSIZE; return 0;} + memcpy(obuf+opos, srcbuf, size); + opos+=size; + return size; + } + else if (hfout!=0) + { +#ifdef ZIP_STD + DWORD writ=(DWORD)fwrite(srcbuf,1,size,hfout); +#else + DWORD writ; WriteFile(hfout,srcbuf,size,&writ,NULL); +#endif + return writ; + } + oerr=ZR_NOTINITED; return 0; +} + +bool TZip::oseek(unsigned int pos) +{ if (!ocanseek) {oerr=ZR_SEEK; return false;} + if (obuf!=0) + { if (pos>=mapsize) {oerr=ZR_MEMSIZE; return false;} + opos=pos; + return true; + } + else if (hfout!=0) + { +#ifdef ZIP_STD + fseek(hfout,pos+ooffset,SEEK_SET); +#else + SetFilePointer(hfout,pos+ooffset,NULL,FILE_BEGIN); +#endif + return true; + } + oerr=ZR_NOTINITED; return 0; +} + +ZRESULT TZip::GetMemory(void **pbuf, unsigned long *plen) +{ // When the user calls GetMemory, they're presumably at the end + // of all their adding. In any case, we have to add the central + // directory now, otherwise the memory we tell them won't be complete. + if (!hasputcen) AddCentral(); hasputcen=true; + if (pbuf!=NULL) *pbuf=(void*)obuf; + if (plen!=NULL) *plen=writ; + if (obuf==NULL) return ZR_NOTMMAP; + return ZR_OK; +} + +ZRESULT TZip::Close() +{ // if the directory hadn't already been added through a call to GetMemory, + // then we do it now + ZRESULT res=ZR_OK; if (!hasputcen) res=AddCentral(); hasputcen=true; +#ifdef ZIP_STD + if (hfout!=0 && mustclosehfout) fclose(hfout); hfout=0; mustclosehfout=false; +#else + if (obuf!=0 && hmapout!=0) UnmapViewOfFile(obuf); obuf=0; + if (hmapout!=0) CloseHandle(hmapout); hmapout=0; + if (hfout!=0 && mustclosehfout) CloseHandle(hfout); hfout=0; mustclosehfout=false; +#endif + return res; +} + + + + +ZRESULT TZip::open_file(const TCHAR *fn) +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; + if (fn==0) return ZR_ARGS; +#ifdef ZIP_STD + HANDLE hf = fopen(fn,"rb"); + if (hf==0) return ZR_NOFILE; + ZRESULT res = open_handle(hf,0); + if (res!=ZR_OK) {fclose(hf); return res;} +#else + HANDLE hf = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (hf==INVALID_HANDLE_VALUE) return ZR_NOFILE; + ZRESULT res = open_handle(hf,0); + if (res!=ZR_OK) {CloseHandle(hf); return res;} +#endif + selfclosehf=true; + return ZR_OK; +} +ZRESULT TZip::open_handle(HANDLE hf,unsigned int len) +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; + if (hf==0 || hf==INVALID_HANDLE_VALUE) return ZR_ARGS; + bool canseek; +#ifdef ZIP_STD + struct stat st; fstat(fileno(hf),&st); canseek = S_ISREG(st.st_mode); +#else + DWORD res = SetFilePointer(hfout,0,0,FILE_CURRENT); + canseek = (res!=0xFFFFFFFF); +#endif + if (canseek) + { ZRESULT res = GetFileInfo(hf,&attr,&isize,×,×tamp); + if (res!=ZR_OK) return res; +#ifdef ZIP_STD + fseek(hf,0,SEEK_SET); +#else + SetFilePointer(hf,0,NULL,FILE_BEGIN); // because GetFileInfo will have screwed it up +#endif + iseekable=true; hfin=hf; + return ZR_OK; + } + else + { attr= 0x80000000; // just a normal file + isize = -1; // can't know size until at the end + if (len!=0) isize=len; // unless we were told explicitly! + iseekable=false; + WORD dosdate, dostime; GetNow(×.atime, &dosdate, &dostime); + times.mtime=times.atime; + times.ctime=times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + hfin=hf; + return ZR_OK; + } +} +ZRESULT TZip::open_mem(void *src,unsigned int len) +{ hfin=0; bufin=(const char*)src; selfclosehf=false; crc=CRCVAL_INITIAL; ired=0; csize=0; ired=0; + lenin=len; posin=0; + if (src==0 || len==0) return ZR_ARGS; + attr= 0x80000000; // just a normal file + isize = len; + iseekable=true; + WORD dosdate, dostime; GetNow(×.atime, &dosdate, &dostime); + times.mtime=times.atime; + times.ctime=times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + return ZR_OK; +} +ZRESULT TZip::open_dir() +{ hfin=0; bufin=0; selfclosehf=false; crc=CRCVAL_INITIAL; isize=0; csize=0; ired=0; + attr= 0x41C00010; // a readable writable directory, and again directory + isize = 0; + iseekable=false; + WORD dosdate, dostime; GetNow(×.atime, &dosdate, &dostime); + times.mtime=times.atime; + times.ctime=times.atime; + timestamp = (WORD)dostime | (((DWORD)dosdate)<<16); + return ZR_OK; +} + +unsigned TZip::sread(TState &s,char *buf,unsigned size) +{ // static + TZip *zip = (TZip*)s.param; + return zip->read(buf,size); +} + +unsigned TZip::read(char *buf, unsigned size) +{ if (bufin!=0) + { if (posin>=lenin) return 0; // end of input + ulg red = lenin-posin; + if (red>size) red=size; + memcpy(buf, bufin+posin, red); + posin += red; + ired += red; + crc = crc32(crc, (uch*)buf, red); + return red; + } + else if (hfin!=0) + { DWORD red; +#ifdef ZIP_STD + red = (DWORD)fread(buf,1,size,hfin); + if (red==0) return 0; +#else + BOOL ok = ReadFile(hfin,buf,size,&red,NULL); + if (!ok) return 0; +#endif + ired += red; + crc = crc32(crc, (uch*)buf, red); + return red; + } + else {oerr=ZR_NOTINITED; return 0;} +} + +ZRESULT TZip::iclose() +{ +#ifdef ZIP_STD + if (selfclosehf && hfin!=0) fclose(hfin); hfin=0; +#else + if (selfclosehf && hfin!=0) CloseHandle(hfin); hfin=0; +#endif + bool mismatch = (isize!=-1 && isize!=ired); + isize=ired; // and crc has been being updated anyway + if (mismatch) return ZR_MISSIZE; + else return ZR_OK; +} + + + +ZRESULT TZip::ideflate(TZipFileInfo *zfi) +{ if (state==0) state=new TState(); + // It's a very big object! 500k! We allocate it on the heap, because PocketPC's + // stack breaks if we try to put it all on the stack. It will be deleted lazily + state->err=0; + state->readfunc=sread; state->flush_outbuf=sflush; + state->param=this; state->level=8; state->seekable=iseekable; state->err=NULL; + // the following line will make ct_init realise it has to perform the init + state->ts.static_dtree[0].dl.len = 0; + // Thanks to Alvin77 for this crucial fix: + state->ds.window_size=0; + // I think that covers everything that needs to be initted. + // + bi_init(*state,buf, sizeof(buf), 1); // it used to be just 1024-size, not 16384 as here + ct_init(*state,&zfi->att); + lm_init(*state,state->level, &zfi->flg); + ulg sz = deflate(*state); + csize=sz; + ZRESULT r=ZR_OK; if (state->err!=NULL) r=ZR_FLATE; + return r; +} + +ZRESULT TZip::istore() +{ ulg size=0; + for (;;) + { unsigned int cin=read(buf,16384); if (cin<=0 || cin==(unsigned int)EOF) break; + unsigned int cout = write(buf,cin); if (cout!=cin) return ZR_MISSIZE; + size += cin; + } + csize=size; + return ZR_OK; +} + + + + + +bool has_seeded=false; +ZRESULT TZip::Add(const TCHAR *odstzn, void *src,unsigned int len, DWORD flags) +{ if (oerr) return ZR_FAILED; + if (hasputcen) return ZR_ENDED; + + // if we use password encryption, then every isize and csize is 12 bytes bigger + int passex=0; if (password!=0 && flags!=ZIP_FOLDER) passex=12; + + // zip has its own notion of what its names should look like: i.e. dir/file.stuff + TCHAR dstzn[MAX_PATH]; _tcsncpy(dstzn,odstzn,MAX_PATH); dstzn[MAX_PATH-1]=0; + if (*dstzn==0) return ZR_ARGS; + TCHAR *d=dstzn; while (*d!=0) {if (*d=='\\') *d='/'; d++;} + bool isdir = (flags==ZIP_FOLDER); + bool needs_trailing_slash = (isdir && dstzn[_tcslen(dstzn)-1]!='/'); + int method=DEFLATE; if (isdir || HasZipSuffix(dstzn)) method=STORE; + + // now open whatever was our input source: + ZRESULT openres; + if (flags==ZIP_FILENAME) openres=open_file((const TCHAR*)src); + else if (flags==ZIP_HANDLE) openres=open_handle((HANDLE)src,len); + else if (flags==ZIP_MEMORY) openres=open_mem(src,len); + else if (flags==ZIP_FOLDER) openres=open_dir(); + else return ZR_ARGS; + if (openres!=ZR_OK) return openres; + + // A zip "entry" consists of a local header (which includes the file name), + // then the compressed data, and possibly an extended local header. + + // Initialize the local header + TZipFileInfo zfi; zfi.nxt=NULL; + strcpy(zfi.name,""); +#ifdef UNICODE + WideCharToMultiByte(CP_UTF8,0,dstzn,-1,zfi.iname,MAX_PATH,0,0); +#else + strncpy(zfi.iname,dstzn,MAX_PATH); zfi.iname[MAX_PATH-1]=0; +#endif + zfi.nam=strlen(zfi.iname); + if (needs_trailing_slash) {strcat(zfi.iname,"/"); zfi.nam++;} + strcpy(zfi.zname,""); + zfi.extra=NULL; zfi.ext=0; // extra header to go after this compressed data, and its length + zfi.cextra=NULL; zfi.cext=0; // extra header to go in the central end-of-zip directory, and its length + zfi.comment=NULL; zfi.com=0; // comment, and its length + zfi.mark = 1; + zfi.dosflag = 0; + zfi.att = (ush)BINARY; + zfi.vem = (ush)0xB17; // 0xB00 is win32 os-code. 0x17 is 23 in decimal: zip 2.3 + zfi.ver = (ush)20; // Needs PKUNZIP 2.0 to unzip it + zfi.tim = timestamp; + // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. + zfi.crc = 0; // to be updated later + zfi.flg = 8; // 8 means 'there is an extra header'. Assume for the moment that we need it. + if (password!=0 && !isdir) zfi.flg=9; // and 1 means 'password-encrypted' + zfi.lflg = zfi.flg; // to be updated later + zfi.how = (ush)method; // to be updated later + zfi.siz = (ulg)(method==STORE && isize>=0 ? isize+passex : 0); // to be updated later + zfi.len = (ulg)(isize); // to be updated later + zfi.dsk = 0; + zfi.atx = attr; + zfi.off = writ+ooffset; // offset within file of the start of this local record + // stuff the 'times' structure into zfi.extra + + // nb. apparently there's a problem with PocketPC CE(zip)->CE(unzip) fails. And removing the following block fixes it up. + char xloc[EB_L_UT_SIZE]; zfi.extra=xloc; zfi.ext=EB_L_UT_SIZE; + char xcen[EB_C_UT_SIZE]; zfi.cextra=xcen; zfi.cext=EB_C_UT_SIZE; + xloc[0] = 'U'; + xloc[1] = 'T'; + xloc[2] = EB_UT_LEN(3); // length of data part of e.f. + xloc[3] = 0; + xloc[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME; + xloc[5] = (char)(times.mtime); + xloc[6] = (char)(times.mtime >> 8); + xloc[7] = (char)(times.mtime >> 16); + xloc[8] = (char)(times.mtime >> 24); + xloc[9] = (char)(times.atime); + xloc[10] = (char)(times.atime >> 8); + xloc[11] = (char)(times.atime >> 16); + xloc[12] = (char)(times.atime >> 24); + xloc[13] = (char)(times.ctime); + xloc[14] = (char)(times.ctime >> 8); + xloc[15] = (char)(times.ctime >> 16); + xloc[16] = (char)(times.ctime >> 24); + memcpy(zfi.cextra,zfi.extra,EB_C_UT_SIZE); + zfi.cextra[EB_LEN] = EB_UT_LEN(1); + + + // (1) Start by writing the local header: + int r = putlocal(&zfi,swrite,this); + if (r!=ZE_OK) {iclose(); return ZR_WRITE;} + writ += 4 + LOCHEAD + (unsigned int)zfi.nam + (unsigned int)zfi.ext; + if (oerr!=ZR_OK) {iclose(); return oerr;} + + // (1.5) if necessary, write the encryption header + keys[0]=305419896L; + keys[1]=591751049L; + keys[2]=878082192L; + for (const char *cp=password; cp!=0 && *cp!=0; cp++) update_keys(keys,*cp); + // generate some random bytes +#ifdef ZIP_STD + if (!has_seeded) srand((unsigned)time(0)); +#else + if (!has_seeded) srand(GetTickCount()^(unsigned long)GetDesktopWindow()); +#endif + char encbuf[12]; for (int i=0; i<12; i++) encbuf[i]=(char)((rand()>>7)&0xff); + encbuf[11] = (char)((zfi.tim>>8)&0xff); + for (int ei=0; ei<12; ei++) encbuf[ei]=zencode(keys,encbuf[ei]); + if (password!=0 && !isdir) {swrite(this,encbuf,12); writ+=12;} + + //(2) Write deflated/stored file to zip file + ZRESULT writeres=ZR_OK; + encwriting = (password!=0 && !isdir); // an object member variable to say whether we write to disk encrypted + if (!isdir && method==DEFLATE) writeres=ideflate(&zfi); + else if (!isdir && method==STORE) writeres=istore(); + else if (isdir) csize=0; + encwriting = false; + iclose(); + writ += csize; + if (oerr!=ZR_OK) return oerr; + if (writeres!=ZR_OK) return ZR_WRITE; + + // (3) Either rewrite the local header with correct information... + bool first_header_has_size_right = (zfi.siz==csize+passex); + zfi.crc = crc; + zfi.siz = csize+passex; + zfi.len = isize; + if (ocanseek && (password==0 || isdir)) + { zfi.how = (ush)method; + if ((zfi.flg & 1) == 0) zfi.flg &= ~8; // clear the extended local header flag + zfi.lflg = zfi.flg; + // rewrite the local header: + if (!oseek(zfi.off-ooffset)) return ZR_SEEK; + if ((r = putlocal(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; + if (!oseek(writ)) return ZR_SEEK; + } + else + { // (4) ... or put an updated header at the end + if (zfi.how != (ush) method) return ZR_NOCHANGE; + if (method==STORE && !first_header_has_size_right) return ZR_NOCHANGE; + if ((r = putextended(&zfi, swrite,this)) != ZE_OK) return ZR_WRITE; + writ += 16L; + zfi.flg = zfi.lflg; // if flg modified by inflate, for the central index + } + if (oerr!=ZR_OK) return oerr; + + // Keep a copy of the zipfileinfo, for our end-of-zip directory + char *cextra = new char[zfi.cext]; memcpy(cextra,zfi.cextra,zfi.cext); zfi.cextra=cextra; + TZipFileInfo *pzfi = new TZipFileInfo; memcpy(pzfi,&zfi,sizeof(zfi)); + if (zfis==NULL) zfis=pzfi; + else {TZipFileInfo *z=zfis; while (z->nxt!=NULL) z=z->nxt; z->nxt=pzfi;} + return ZR_OK; +} + +ZRESULT TZip::AddCentral() +{ // write central directory + int numentries = 0; + ulg pos_at_start_of_central = writ; + //ulg tot_unc_size=0, tot_compressed_size=0; + bool okay=true; + for (TZipFileInfo *zfi=zfis; zfi!=NULL; ) + { if (okay) + { int res = putcentral(zfi, swrite,this); + if (res!=ZE_OK) okay=false; + } + writ += 4 + CENHEAD + (unsigned int)zfi->nam + (unsigned int)zfi->cext + (unsigned int)zfi->com; + //tot_unc_size += zfi->len; + //tot_compressed_size += zfi->siz; + numentries++; + // + TZipFileInfo *zfinext = zfi->nxt; + if (zfi->cextra!=0) delete[] zfi->cextra; + delete zfi; + zfi = zfinext; + } + ulg center_size = writ - pos_at_start_of_central; + if (okay) + { int res = putend(numentries, center_size, pos_at_start_of_central+ooffset, 0, NULL, swrite,this); + if (res!=ZE_OK) okay=false; + writ += 4 + ENDHEAD + 0; + } + if (!okay) return ZR_WRITE; + return ZR_OK; +} + + + + + +ZRESULT lasterrorZ=ZR_OK; + +unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len) +{ if (code==ZR_RECENT) code=lasterrorZ; + const char *msg="unknown zip result code"; + switch (code) + { case ZR_OK: msg="Success"; break; + case ZR_NODUPH: msg="Culdn't duplicate handle"; break; + case ZR_NOFILE: msg="Couldn't create/open file"; break; + case ZR_NOALLOC: msg="Failed to allocate memory"; break; + case ZR_WRITE: msg="Error writing to file"; break; + case ZR_NOTFOUND: msg="File not found in the zipfile"; break; + case ZR_MORE: msg="Still more data to unzip"; break; + case ZR_CORRUPT: msg="Zipfile is corrupt or not a zipfile"; break; + case ZR_READ: msg="Error reading file"; break; + case ZR_ARGS: msg="Caller: faulty arguments"; break; + case ZR_PARTIALUNZ: msg="Caller: the file had already been partially unzipped"; break; + case ZR_NOTMMAP: msg="Caller: can only get memory of a memory zipfile"; break; + case ZR_MEMSIZE: msg="Caller: not enough space allocated for memory zipfile"; break; + case ZR_FAILED: msg="Caller: there was a previous error"; break; + case ZR_ENDED: msg="Caller: additions to the zip have already been ended"; break; + case ZR_ZMODE: msg="Caller: mixing creation and opening of zip"; break; + case ZR_NOTINITED: msg="Zip-bug: internal initialisation not completed"; break; + case ZR_SEEK: msg="Zip-bug: trying to seek the unseekable"; break; + case ZR_MISSIZE: msg="Zip-bug: the anticipated size turned out wrong"; break; + case ZR_NOCHANGE: msg="Zip-bug: tried to change mind, but not allowed"; break; + case ZR_FLATE: msg="Zip-bug: an internal error during flation"; break; + } + unsigned int mlen=(unsigned int)strlen(msg); + if (buf==0 || len==0) return mlen; + unsigned int n=mlen; if (n+1>len) n=len-1; + strncpy(buf,msg,n); buf[n]=0; + return mlen; +} + + + +typedef struct +{ DWORD flag; + TZip *zip; +} TZipHandleData; + + +HZIP CreateZipInternal(void *z,unsigned int len,DWORD flags, const char *password) +{ TZip *zip = new TZip(password); + lasterrorZ = zip->Create(z,len,flags); + if (lasterrorZ!=ZR_OK) {delete zip; return 0;} + TZipHandleData *han = new TZipHandleData; + han->flag=2; han->zip=zip; return (HZIP)han; +} +HZIP CreateZipHandle(HANDLE h, const char *password) {return CreateZipInternal(h,0,ZIP_HANDLE,password);} +HZIP CreateZip(const TCHAR *fn, const char *password) {return CreateZipInternal((void*)fn,0,ZIP_FILENAME,password);} +HZIP CreateZip(void *z,unsigned int len, const char *password) {return CreateZipInternal(z,len,ZIP_MEMORY,password);} + + +ZRESULT ZipAddInternal(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len, DWORD flags) +{ if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} + TZip *zip = han->zip; + lasterrorZ = zip->Add(dstzn,src,len,flags); + return lasterrorZ; +} +ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn) {return ZipAddInternal(hz,dstzn,(void*)fn,0,ZIP_FILENAME);} +ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len) {return ZipAddInternal(hz,dstzn,src,len,ZIP_MEMORY);} +ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h) {return ZipAddInternal(hz,dstzn,h,0,ZIP_HANDLE);} +ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len) {return ZipAddInternal(hz,dstzn,h,len,ZIP_HANDLE);} +ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn) {return ZipAddInternal(hz,dstzn,0,0,ZIP_FOLDER);} + + + +ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len) +{ if (hz==0) {if (buf!=0) *buf=0; if (len!=0) *len=0; lasterrorZ=ZR_ARGS;return ZR_ARGS;} + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} + TZip *zip = han->zip; + lasterrorZ = zip->GetMemory(buf,len); + return lasterrorZ; +} + +ZRESULT CloseZipZ(HZIP hz) +{ if (hz==0) {lasterrorZ=ZR_ARGS;return ZR_ARGS;} + TZipHandleData *han = (TZipHandleData*)hz; + if (han->flag!=2) {lasterrorZ=ZR_ZMODE;return ZR_ZMODE;} + TZip *zip = han->zip; + lasterrorZ = zip->Close(); + delete zip; + delete han; + return lasterrorZ; +} + +bool IsZipHandleZ(HZIP hz) +{ if (hz==0) return false; + TZipHandleData *han = (TZipHandleData*)hz; + return (han->flag==2); +} + diff --git a/datafile/zip/zip.h b/datafile/zip/zip.h new file mode 100644 index 0000000..ab586fa --- /dev/null +++ b/datafile/zip/zip.h @@ -0,0 +1,214 @@ +#ifndef _zip_H +#define _zip_H +// +#ifdef ZIP_STD +#include +#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#ifndef MAX_PATH +#define MAX_PATH 1024 +#endif +typedef unsigned long DWORD; +typedef char TCHAR; +typedef FILE* HANDLE; +typedef time_t FILETIME; +#endif + +// ZIP functions -- for creating zip files +// This file is a repackaged form of the Info-Zip source code available +// at www.info-zip.org. The original copyright notice may be found in +// zip.cpp. The repackaging was done by Lucian Wischik to simplify and +// extend its use in Windows/C++. Also to add encryption and unicode. + + +#ifndef _unzip_H +DECLARE_HANDLE(HZIP); +#endif +// An HZIP identifies a zip file that is being created + +typedef DWORD ZRESULT; +// return codes from any of the zip functions. Listed later. + + + +HZIP CreateZip(const TCHAR *fn, const char *password); +HZIP CreateZip(void *buf,unsigned int len, const char *password); +HZIP CreateZipHandle(HANDLE h, const char *password); +// CreateZip - call this to start the creation of a zip file. +// As the zip is being created, it will be stored somewhere: +// to a pipe: CreateZipHandle(hpipe_write); +// in a file (by handle): CreateZipHandle(hfile); +// in a file (by name): CreateZip("c:\\test.zip"); +// in memory: CreateZip(buf, len); +// or in pagefile memory: CreateZip(0, len); +// The final case stores it in memory backed by the system paging file, +// where the zip may not exceed len bytes. This is a bit friendlier than +// allocating memory with new[]: it won't lead to fragmentation, and the +// memory won't be touched unless needed. That means you can give very +// large estimates of the maximum-size without too much worry. +// As for the password, it lets you encrypt every file in the archive. +// (This api doesn't support per-file encryption.) +// Note: because pipes don't allow random access, the structure of a zipfile +// created into a pipe is slightly different from that created into a file +// or memory. In particular, the compressed-size of the item cannot be +// stored in the zipfile until after the item itself. (Also, for an item added +// itself via a pipe, the uncompressed-size might not either be known until +// after.) This is not normally a problem. But if you try to unzip via a pipe +// as well, then the unzipper will not know these things about the item until +// after it has been unzipped. Therefore: for unzippers which don't just write +// each item to disk or to a pipe, but instead pre-allocate memory space into +// which to unzip them, then either you have to create the zip not to a pipe, +// or you have to add items not from a pipe, or at least when adding items +// from a pipe you have to specify the length. +// Note: for windows-ce, you cannot close the handle until after CloseZip. +// but for real windows, the zip makes its own copy of your handle, so you +// can close yours anytime. + + +ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, const TCHAR *fn); +ZRESULT ZipAdd(HZIP hz,const TCHAR *dstzn, void *src,unsigned int len); +ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h); +ZRESULT ZipAddHandle(HZIP hz,const TCHAR *dstzn, HANDLE h, unsigned int len); +ZRESULT ZipAddFolder(HZIP hz,const TCHAR *dstzn); +// ZipAdd - call this for each file to be added to the zip. +// dstzn is the name that the file will be stored as in the zip file. +// The file to be added to the zip can come +// from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read); +// from a file: ZipAddHandle(hz,"file.dat", hfile); +// from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat"); +// from memory: ZipAdd(hz,"subdir\\file.dat", buf,len); +// (folder): ZipAddFolder(hz,"subdir"); +// Note: if adding an item from a pipe, and if also creating the zip file itself +// to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle +// function. This will let the zipfile store the item's size ahead of the +// compressed item itself, which in turn makes it easier when unzipping the +// zipfile from a pipe. + +ZRESULT ZipGetMemory(HZIP hz, void **buf, unsigned long *len); +// ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len), +// then this function will return information about that memory block. +// buf will receive a pointer to its start, and len its length. +// Note: you can't add any more after calling this. + +ZRESULT CloseZip(HZIP hz); +// CloseZip - the zip handle must be closed with this function. + +unsigned int FormatZipMessage(ZRESULT code, TCHAR *buf,unsigned int len); +// FormatZipMessage - given an error code, formats it as a string. +// It returns the length of the error message. If buf/len points +// to a real buffer, then it also writes as much as possible into there. + + + +// These are the result codes: +#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, +#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. +// The following come from general system stuff (e.g. files not openable) +#define ZR_GENMASK 0x0000FF00 +#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle +#define ZR_NOFILE 0x00000200 // couldn't create/open the file +#define ZR_NOALLOC 0x00000300 // failed to allocate some resource +#define ZR_WRITE 0x00000400 // a general error writing to the file +#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip +#define ZR_MORE 0x00000600 // there's still more data to be unzipped +#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile +#define ZR_READ 0x00000800 // a general error reading the file +// The following come from mistakes on the part of the caller +#define ZR_CALLERMASK 0x00FF0000 +#define ZR_ARGS 0x00010000 // general mistake with the arguments +#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't +#define ZR_MEMSIZE 0x00030000 // the memory size is too small +#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function +#define ZR_ENDED 0x00050000 // the zip creation has already been closed +#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken +#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped +#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip +// The following come from bugs within the zip library itself +#define ZR_BUGMASK 0xFF000000 +#define ZR_NOTINITED 0x01000000 // initialisation didn't work +#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file +#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed +#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code + + + + + + +// e.g. +// +// (1) Traditional use, creating a zipfile from existing files +// HZIP hz = CreateZip("c:\\simple1.zip",0); +// ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp"); +// ZipAdd(hz,"znsimple.txt", "c:\\simple.txt"); +// CloseZip(hz); +// +// (2) Memory use, creating an auto-allocated mem-based zip file from various sources +// HZIP hz = CreateZip(0,100000, 0); +// // adding a conventional file... +// ZipAdd(hz,"src1.txt", "c:\\src1.txt"); +// // adding something from memory... +// char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F); +// ZipAdd(hz,"file.dat", buf,1000); +// // adding something from a pipe... +// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0); +// HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0); +// ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional. +// WaitForSingleObject(hthread,INFINITE); +// CloseHandle(hthread); CloseHandle(hread); +// ... meanwhile DWORD WINAPI ThreadFunc(void *dat) +// { HANDLE hwrite = (HANDLE)dat; +// char buf[1000]={17}; +// DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL); +// CloseHandle(hwrite); +// return 0; +// } +// // and now that the zip is created, let's do something with it: +// void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen); +// HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); +// DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL); +// CloseHandle(hfz); +// CloseZip(hz); +// +// (3) Handle use, for file handles and pipes +// HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0); +// HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0); +// HZIP hz = CreateZipHandle(hzwrite,0); +// // ... add to it +// CloseZip(hz); +// CloseHandle(hzwrite); +// WaitForSingleObject(hthread,INFINITE); +// CloseHandle(hthread); +// ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat) +// { HANDLE hread = (HANDLE)dat; +// char buf[1000]; +// while (true) +// { DWORD red; ReadFile(hread,buf,1000,&red,NULL); +// // ... and do something with this zip data we're receiving +// if (red==0) break; +// } +// CloseHandle(hread); +// return 0; +// } + + + +// Now we indulge in a little skullduggery so that the code works whether +// the user has included just zip or both zip and unzip. +// Idea: if header files for both zip and unzip are present, then presumably +// the cpp files for zip and unzip are both present, so we will call +// one or the other of them based on a dynamic choice. If the header file +// for only one is present, then we will bind to that particular one. +ZRESULT CloseZipZ(HZIP hz); +unsigned int FormatZipMessageZ(ZRESULT code, char *buf,unsigned int len); +bool IsZipHandleZ(HZIP hz); +#ifdef _unzip_H +#undef CloseZip +#define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz)) +#else +#define CloseZip CloseZipZ +#define FormatZipMessage FormatZipMessageZ +#endif + + + +#endif diff --git a/datafile/zip/zipreader.cpp b/datafile/zip/zipreader.cpp new file mode 100644 index 0000000..3ba26d8 --- /dev/null +++ b/datafile/zip/zipreader.cpp @@ -0,0 +1,89 @@ +#include "zipreader.h" + +#include + +ZipReader::ZipReader(const QString &filePath) : +#ifdef UNICODE + m_reader(OpenZip(reinterpret_cast(filePath.utf16()),nullptr)) +#else + m_reader(OpenZip(filePath.toUtf8().constData(),nullptr)) +#endif +{ + init(); +} + +ZipReader::ZipReader(QIODevice *device) +{ + QFile *file = dynamic_cast(device); + if(nullptr != file) + { + QString strFile = file->fileName(); + file->close(); +#ifdef UNICODE + m_reader = OpenZip(reinterpret_cast(strFile.utf16()),nullptr); +#else + m_reader = OpenZip(strFile.toUtf8().constData(),nullptr); +#endif + } + else + { + m_reader = OpenZip(device->readAll().data(),device->size(),nullptr); + } + + init(); +} + +ZipReader::~ZipReader() +{ + CloseZip(m_reader); +} + +void ZipReader::init() +{ + ZIPENTRY entry; + GetZipItem(m_reader,-1,&entry); + int nItems = entry.index; + for(int zi=0; zi +#include + +#if QT_VERSION >= 0x050600 + #include +#endif + +#include "unzip.h" + +class ZipReader +{ +public: + explicit ZipReader(const QString &fileName); + explicit ZipReader(QIODevice *device); + ~ZipReader(); + bool exists() const; + QStringList filePaths() const; + QByteArray fileData(const QString &fileName) const; + +private: + Q_DISABLE_COPY(ZipReader) + void init(); + HZIP m_reader; + QStringList m_filePaths; +}; + +#endif // ZIPREADER_H diff --git a/datafile/zip/zipwriter.cpp b/datafile/zip/zipwriter.cpp new file mode 100644 index 0000000..2dacbd5 --- /dev/null +++ b/datafile/zip/zipwriter.cpp @@ -0,0 +1,70 @@ +#include "zipwriter.h" + +#include +#include +#include + +ZipWriter::ZipWriter(const QString &filePath) +{ +#ifdef UNICODE + std::wstring strPath = filePath.toStdWString(); + m_writer = CreateZip(strPath.c_str(),nullptr); +#else + m_writer = CreateZip(strFile.toUtf8().constData(),nullptr); +#endif +} + +ZipWriter::ZipWriter(QIODevice *device) +{ + QFile *file = dynamic_cast(device); + if(nullptr != file) + { + QString strFile = file->fileName(); + file->close(); +#ifdef UNICODE + m_writer = CreateZip(reinterpret_cast(strFile.utf16()),nullptr); +#else + m_writer = CreateZip(strFile.toUtf8().constData(),nullptr); +#endif + } + else + { + m_writer =0; + } +} +ZipWriter::~ZipWriter() +{ + CloseZip( m_writer); +} + +bool ZipWriter::error() const +{ + return !IsZipHandleZ(m_writer); +} + +void ZipWriter::addFile(const QString &filePath, QIODevice *device) +{ +#ifdef UNICODE + std::wstring strFilePath = filePath.toStdWString(); + ZipAdd(m_writer,strFilePath.c_str(),(void*)device->readAll().data(),device->size()); +#else + ZipAdd(m_writer,filePath.toUtf8().constData(),(void*)device->readAll().data(),device->size()); +#endif + +} + +void ZipWriter::addFile(const QString &filePath, const QByteArray &data) +{ +#ifdef UNICODE + std::wstring strFilePath = filePath.toStdWString(); + ZipAdd(m_writer,strFilePath.c_str(),(void*)data.data(),data.size()); +#else + ZipAdd(m_writer,filePath.toUtf8().constData(),(void*)data.data(),data.size()); +#endif + +} + +void ZipWriter::close() +{ + CloseZip( m_writer); +} diff --git a/datafile/zip/zipwriter.h b/datafile/zip/zipwriter.h new file mode 100644 index 0000000..b0fcfc2 --- /dev/null +++ b/datafile/zip/zipwriter.h @@ -0,0 +1,27 @@ +#ifndef ZIPWRITER_H +#define ZIPWRITER_H + +#include +#include +#include + +#include "zip.h" + +class ZipWriter +{ +public: + explicit ZipWriter(const QString &filePath); + explicit ZipWriter(QIODevice *device); + ~ZipWriter(); + + void addFile(const QString &filePath, QIODevice *device); + void addFile(const QString &filePath, const QByteArray &data); + bool error() const; + void close(); + +private: + HZIP m_writer; + ZRESULT m_result; +}; + +#endif // ZIPWRITER_H diff --git a/drawingsetdialog.cpp b/drawingsetdialog.cpp new file mode 100644 index 0000000..3e5161b --- /dev/null +++ b/drawingsetdialog.cpp @@ -0,0 +1,16 @@ +#include "drawingsetdialog.h" +#include "ui_drawingsetdialog.h" + +DrawingSetDialog::DrawingSetDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::DrawingSetDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); +} + +DrawingSetDialog::~DrawingSetDialog() +{ + delete ui; +} diff --git a/drawingsetdialog.h b/drawingsetdialog.h new file mode 100644 index 0000000..73bc423 --- /dev/null +++ b/drawingsetdialog.h @@ -0,0 +1,22 @@ +#ifndef DRAWINGSETDIALOG_H +#define DRAWINGSETDIALOG_H + +#include + +namespace Ui { +class DrawingSetDialog; +} + +class DrawingSetDialog : public QDialog +{ + Q_OBJECT + +public: + explicit DrawingSetDialog(QWidget *parent = 0); + ~DrawingSetDialog(); + +private: + Ui::DrawingSetDialog *ui; +}; + +#endif // DRAWINGSETDIALOG_H diff --git a/drawingsetdialog.ui b/drawingsetdialog.ui new file mode 100644 index 0000000..4f0e267 --- /dev/null +++ b/drawingsetdialog.ui @@ -0,0 +1,356 @@ + + + DrawingSetDialog + + + + 0 + 0 + 346 + 370 + + + + Dialog + + + + + 30 + 40 + 221 + 20 + + + + Use vector fonts + + + + + + 30 + 12 + 291 + 20 + + + + Graph positive rotation angle + + + + + + 190 + 326 + 60 + 26 + + + + Ok + + + + + + 20 + 190 + 306 + 121 + + + + Boundary and alignment spacing + + + + + 270 + 30 + 30 + 12 + + + + mm + + + + + + 200 + 26 + 61 + 20 + + + + 0 + + + + + + 33 + 26 + 111 + 20 + + + + Right margin: + + + + + + 200 + 56 + 61 + 20 + + + + 0 + + + + + + 270 + 60 + 30 + 12 + + + + mm + + + + + + 33 + 56 + 111 + 20 + + + + Mark margin: + + + + + + 33 + 86 + 151 + 20 + + + + Butt joint margin: + + + + + + 270 + 90 + 30 + 12 + + + + mm + + + + + + 200 + 86 + 61 + 20 + + + + 1000 + + + + + + 10 + 30 + 16 + 16 + + + + background-image: url(:/resources/right_ga.bmp); + + + + + + + + + 10 + 60 + 16 + 16 + + + + background-image: url(:/resources/down_gap.bmp); + + + + + + + + + 10 + 90 + 16 + 16 + + + + background-image: url(:/resources/mark_gap.bmp); + + + + + + + + + + 20 + 130 + 306 + 51 + + + + Paper Width + + + + + 170 + 24 + 54 + 12 + + + + mm + + + + + + 70 + 20 + 91 + 20 + + + + 2400 + + + + + + 10 + 20 + 42 + 20 + + + + background-image: url(:/resources/page_cy.bmp); + + + + + + + + + + 260 + 326 + 60 + 26 + + + + Cancel + + + + + + 20 + 70 + 306 + 51 + + + + Lineweight settings + + + + + 13 + 20 + 91 + 20 + + + + Lineweight: + + + + + + 110 + 20 + 91 + 20 + + + + 2 + + + + + + 210 + 19 + 61 + 21 + + + + pixel + + + + + + + diff --git a/historydialog.cpp b/historydialog.cpp new file mode 100644 index 0000000..b258d05 --- /dev/null +++ b/historydialog.cpp @@ -0,0 +1,16 @@ +#include "historydialog.h" +#include "ui_historydialog.h" + +HistoryDialog::HistoryDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::HistoryDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); +} + +HistoryDialog::~HistoryDialog() +{ + delete ui; +} diff --git a/historydialog.h b/historydialog.h new file mode 100644 index 0000000..51f838a --- /dev/null +++ b/historydialog.h @@ -0,0 +1,22 @@ +#ifndef HISTORYDIALOG_H +#define HISTORYDIALOG_H + +#include + +namespace Ui { +class HistoryDialog; +} + +class HistoryDialog : public QDialog +{ + Q_OBJECT + +public: + explicit HistoryDialog(QWidget *parent = 0); + ~HistoryDialog(); + +private: + Ui::HistoryDialog *ui; +}; + +#endif // HISTORYDIALOG_H diff --git a/historydialog.ui b/historydialog.ui new file mode 100644 index 0000000..c0d5963 --- /dev/null +++ b/historydialog.ui @@ -0,0 +1,68 @@ + + + HistoryDialog + + + + 0 + 0 + 540 + 460 + + + + Dialog + + + + + 400 + 430 + 60 + 26 + + + + Clear + + + + + + 10 + 10 + 521 + 411 + + + + + + + 470 + 430 + 60 + 26 + + + + Cancel + + + + + + 330 + 430 + 60 + 26 + + + + Draw + + + + + + diff --git a/include/qrencode.h b/include/qrencode.h new file mode 100644 index 0000000..164af41 --- /dev/null +++ b/include/qrencode.h @@ -0,0 +1,568 @@ +/** + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2017 Kentaro Fukuchi + * + * This library 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 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** \mainpage + * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D + * symbology. + * + * \section encoding Encoding + * + * There are two methods to encode data: encoding a string/data or + * encoding a structured data. + * + * \subsection encoding-string Encoding a string/data + * You can encode a string by calling QRcode_encodeString(). + * The given string is parsed automatically and encoded. If you want to encode + * data that can be represented as a C string style (NUL terminated), you can + * simply use this way. + * + * If the input data contains Kanji (Shift-JIS) characters and you want to + * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint. + * Otherwise, all of non-alphanumeric characters are encoded as 8 bit data. + * If you want to encode a whole string in 8 bit mode, you can use + * QRcode_encodeString8bit() instead. + * + * Please note that a C string can not contain NUL characters. If your data + * contains NUL, you must use QRcode_encodeData(). + * + * \subsection encoding-input Encoding a structured data + * You can construct a structured input data manually. If the structure of the + * input data is known, you can use this way. + * At first, create a ::QRinput object by QRinput_new(). Then add input data + * to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput() + * to encode the QRinput data. + * You can reuse the QRinput data again to encode it in other symbols with + * different parameters. + * + * \section result Result + * The encoded symbol is resulted as a ::QRcode object. It will contain + * its version number, width of the symbol and an array represents the symbol. + * See ::QRcode for the details. You can free the object by QRcode_free(). + * + * Please note that the version of the result may be larger than specified. + * In such cases, the input data would be too large to be encoded in a + * symbol of the specified version. + * + * \section structured Structured append + * Libqrencode can generate "Structured-appended" symbols that enables to split + * a large data set into mulitple QR codes. A QR code reader concatenates + * multiple QR code symbols into a string. + * Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured() + * to generate structured-appended symbols. This functions returns an instance + * of ::QRcode_List. The returned list is a singly-linked list of QRcode: you + * can retrieve each QR code in this way: + * + * \code + * QRcode_List *qrcodes; + * QRcode_List *entry; + * QRcode *qrcode; + * + * qrcodes = QRcode_encodeStringStructured(...); + * entry = qrcodes; + * while(entry != NULL) { + * qrcode = entry->code; + * // do something + * entry = entry->next; + * } + * QRcode_List_free(entry); + * \endcode + * + * Instead of using auto-parsing functions, you can construct your own + * structured input. At first, instantiate an object of ::QRinput_Struct + * by calling QRinput_Struct_new(). This object can hold multiple ::QRinput, + * and one QR code is generated for a ::QRinput. + * QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct + * object. In order to generate structured-appended symbols, it is required to + * embed headers to each symbol. You can use + * QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate + * headers to each symbol. You should call this function just once before + * encoding symbols. + */ + +#ifndef QRENCODE_H +#define QRENCODE_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encoding mode. + */ +typedef enum { + QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only + QR_MODE_NUM = 0, ///< Numeric mode + QR_MODE_AN, ///< Alphabet-numeric mode + QR_MODE_8, ///< 8-bit data mode + QR_MODE_KANJI, ///< Kanji (shift-jis) mode + QR_MODE_STRUCTURE, ///< Internal use only + QR_MODE_ECI, ///< ECI mode + QR_MODE_FNC1FIRST, ///< FNC1, first position + QR_MODE_FNC1SECOND, ///< FNC1, second position +} QRencodeMode; + +/** + * Level of error correction. + */ +typedef enum { + QR_ECLEVEL_L = 0, ///< lowest + QR_ECLEVEL_M, + QR_ECLEVEL_Q, + QR_ECLEVEL_H ///< highest +} QRecLevel; + +/** + * Maximum version (size) of QR-code symbol. + */ +#define QRSPEC_VERSION_MAX 40 + +/** + * Maximum version (size) of QR-code symbol. + */ +#define MQRSPEC_VERSION_MAX 4 + + +/****************************************************************************** + * Input data (qrinput.c) + *****************************************************************************/ + +/** + * Singly linked list to contain input strings. An instance of this class + * contains its version and error correction level too. It is required to + * set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(), + * or use QRinput_new2() to instantiate an object. + */ +typedef struct _QRinput QRinput; + +/** + * Instantiate an input data object. The version is set to 0 (auto-select) + * and the error correction level is set to QR_ECLEVEL_L. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput *QRinput_new(void); + +/** + * Instantiate an input data object. + * @param version version number. + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_new2(int version, QRecLevel level); + +/** + * Instantiate an input data object. Object's Micro QR Code flag is set. + * Unlike with full-sized QR Code, version number must be specified (>0). + * @param version version number (1--4). + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_newMQR(int version, QRecLevel level); + +/** + * Append data to an input object. + * The data is copied and appended to the input object. + * @param input input object. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data); + +/** + * Append ECI header. + * @param input input object. + * @param ecinum ECI indicator number (0 - 999999) + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum); + +/** + * Get current version. + * @param input input object. + * @return current version. + */ +extern int QRinput_getVersion(QRinput *input); + +/** + * Set version of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersion(QRinput *input, int version); + +/** + * Get current error correction level. + * @param input input object. + * @return Current error correcntion level. + */ +extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input); + +/** + * Set error correction level of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level); + +/** + * Set version and error correction level of the QR code at once. + * This function is recommened for Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level); + +/** + * Free the input object. + * All of data chunks in the input object are freed too. + * @param input input object. + */ +extern void QRinput_free(QRinput *input); + +/** + * Validate the input data. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 invalid arguments. + */ +extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data); + +/** + * Set of QRinput for structured symbols. + */ +typedef struct _QRinput_Struct QRinput_Struct; + +/** + * Instantiate a set of input data object. + * @return an instance of QRinput_Struct. On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_Struct_new(void); + +/** + * Set parity of structured symbols. + * @param s structured input object. + * @param parity parity of s. + */ +extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity); + +/** + * Append a QRinput object to the set. QRinput created by QRinput_newMQR() + * will be rejected. + * @warning never append the same QRinput object twice or more. + * @param s structured input object. + * @param input an input object. + * @retval >0 number of input objects in the structure. + * @retval -1 an error occurred. See Exceptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid arguments. + */ +extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input); + +/** + * Free all of QRinput in the set. + * @param s a structured input object. + */ +extern void QRinput_Struct_free(QRinput_Struct *s); + +/** + * Split a QRinput to QRinput_Struct. It calculates a parity, set it, then + * insert structured-append headers. QRinput created by QRinput_newMQR() will + * be rejected. + * @param input input object. Version number and error correction level must be + * set. + * @return a set of input data. On error, NULL is returned, and errno is set + * to indicate the error. See Exceptions for the details. + * @throw ERANGE input data is too large. + * @throw EINVAL invalid input data. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input); + +/** + * Insert structured-append headers to the input structure. It calculates + * a parity and set it if the parity is not set yet. + * @param s input structure + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory. + */ +extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s); + +/** + * Set FNC1-1st position flag. + */ +extern int QRinput_setFNC1First(QRinput *input); + +/** + * Set FNC1-2nd position flag and application identifier. + */ +extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid); + +/****************************************************************************** + * QRcode output (qrencode.c) + *****************************************************************************/ + +/** + * QRcode class. + * Symbol data is represented as an array contains width*width uchars. + * Each uchar represents a module (dot). If the less significant bit of + * the uchar is 1, the corresponding module is black. The other bits are + * meaningless for usual applications, but here its specification is described. + * + * @verbatim + MSB 76543210 LSB + |||||||`- 1=black/0=white + ||||||`-- data and ecc code area + |||||`--- format information + ||||`---- version information + |||`----- timing pattern + ||`------ alignment pattern + |`------- finder pattern and separator + `-------- non-data modules (format, timing, etc.) + @endverbatim + */ +typedef struct { + int version; ///< version of the symbol + int width; ///< width of the symbol + unsigned char *data; ///< symbol data +} QRcode; + +/** + * Singly-linked list of QRcode. Used to represent a structured symbols. + * A list is terminated with NULL. + */ +typedef struct _QRcode_List { + QRcode *code; + struct _QRcode_List *next; +} QRcode_List; + +/** + * Create a symbol from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param input input data. + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode *QRcode_encodeInput(QRinput *input); + +/** + * Create a symbol from the string. The library automatically parses the input + * string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeString(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeString(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Micro QR Code version of QRcode_encodeString8bit(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level); + +/** + * Encode byte stream (may include '\0') in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input data. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeData(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Free the instance of QRcode class. + * @param qrcode an instance of QRcode class. + */ +extern void QRcode_free(QRcode *qrcode); + +/** + * Create structured symbols from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param s input data, structured. + * @return a singly-linked list of QRcode. + */ +extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s); + +/** + * Create structured symbols from the string. The library automatically parses + * the input string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. + * @param level error correction level. + * @param hint tell the library how Japanese Kanji characters should be + * encoded. If QR_MODE_KANJI is given, the library assumes that the + * given string contains Shift-JIS characters and encodes them in + * Kanji-mode. If QR_MODE_8 is given, all of non-alphanumerical + * characters will be encoded as is. If you want to embed UTF-8 + * string, choose this. Other mode will cause EINVAL error. + * @param casesensitive case-sensitive(1) or not(0). + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level); + +/** + * Create structured symbols from byte stream (may include '\0'). Wholde data + * are encoded in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input dat. + * @param version version of the symbol. + * @param level error correction level. + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Return the number of symbols included in a QRcode_List. + * @param qrlist a head entry of a QRcode_List. + * @return number of symbols in the list. + */ +extern int QRcode_List_size(QRcode_List *qrlist); + +/** + * Free the QRcode_List. + * @param qrlist a head entry of a QRcode_List. + */ +extern void QRcode_List_free(QRcode_List *qrlist); + + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +/** + * Return a string that identifies the library version. + * @param major_version major version number + * @param minor_version minor version number + * @param micro_version micro version number + */ +extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version); + +/** + * Return a string that identifies the library version. + * @return a string identifies the library version. The string is held by the + * library. Do NOT free it. + */ +extern char *QRcode_APIVersionString(void); + +/** + * @deprecated + */ +#ifndef _MSC_VER +extern void QRcode_clearCache(void) __attribute__ ((deprecated)); +#else +extern void QRcode_clearCache(void); +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* QRENCODE_H */ diff --git a/lib/libqrencode.a b/lib/libqrencode.a new file mode 100644 index 0000000000000000000000000000000000000000..2c0700d0eb00224fb66c3f3bfb55f165c3a5b534 GIT binary patch literal 51502 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 literal 0 HcmV?d00001 diff --git a/machine/bmp/bwbmp.cpp b/machine/bmp/bwbmp.cpp new file mode 100644 index 0000000..a3dd146 --- /dev/null +++ b/machine/bmp/bwbmp.cpp @@ -0,0 +1,604 @@ +#include "bwbmp.h" +#include + +#include + + +BWBmp::BWBmp() +{ + +} + +int BWBmp::LoadBiBmp(QString filename) +{ + m_bwDdat.clear(); + m_prDdat.clear(); + + QFile file(filename); + int rslt = file.open(QFile::ReadOnly); + if (rslt == 0) + { + qDebug() << "open file error" << filename; + return -1; + } + + m_bwDdat = file.readAll(); + if (m_bwDdat.size() <= (int)sizeof(BitmapHead)) + { + m_bwDdat.clear(); + file.close(); + + qDebug() << "file size error, size=" << m_bwDdat.size(); + return -2; + } + + BitmapHead * pHead = (BitmapHead *)(m_bwDdat.data()); + + if ( (pHead->identifier != 0x4d42) || + (pHead->bitDatOffset != 0x3E) || + (pHead->biSize != 0x28) || + (pHead->biPlanes != 0x01) || + (pHead->biBitPerPixel != 0x01) || + (pHead->biCompression != 0x00) || + 0 ) + { + m_bwDdat.clear(); + file.close(); + + qDebug() << "not bi bmp"; + return -3; + } + + file.close(); + return 0; +} + + +int BWBmp::SavePrBmp(QString filename) +{ + QFile file(filename); + int rslt = file.open(QFile::ReadWrite | QFile::Truncate); + if (rslt == 0) + { + qDebug() << "open file error" << filename; + return -1; + } + + file.write(m_prDdat); + file.close(); + + return 0; +} + + + +int BWBmp::Compress(int dir) +{ + /* + 为了减少喷墨绘图仪的数据传输量,对黑白位图数据进行压缩。 + 压缩算法如下: + + 每个墨盒的位图数据宽度为300像素,高度不确定 + + 每个字节分为两段 + 用属性+值 的方式表示 + __________________________________________________ + | bit7 bit6 | bit5 bit4 bit3 bit2 bit1 bit0 | + -------------------------------------------------- + | 属性 | 值 | + -------------------------------------------------- + | 0 0 | 原始数据 | + -------------------------------------------------- + | 0 1 | 连续数据1的个数 | + -------------------------------------------------- + | 1 0 | 连续10个数据0的个数 | + -------------------------------------------------- + | 1 1 | 连续数据0的个数 | + -------------------------------------------------- + */ + + if (dir < 0) + { + dir = -1; + } + else + { + dir = 1; + } + + m_prDdat.clear(); + if (m_bwDdat.isEmpty() == 1) + { + qDebug() << "bit dat empty"; + return -1; + } + + BitmapHead * pHead = (BitmapHead *)(m_bwDdat.data()); + + int width = pHead->biWidth; + int height = pHead->biHeight; + int widthBytes = (int)((width + 31) / 32) * 4; + + if (widthBytes <= 0 || height < 1 || width > 0x1000000) + { + qDebug() << "bit dat error"; + return -2; + } + + const unsigned char * pBitDat = (unsigned char *)(m_bwDdat.data() + pHead->bitDatOffset); + + const unsigned char * pTmpDat; + + if (dir == -1) + { + pBitDat += widthBytes * (height -1); + } + + int * countBuff = new int [width]; + if (countBuff == NULL) + { + qDebug() << "no enough memory"; + return -3; + } + memset(countBuff, 0, sizeof(int)*width); + + unsigned char tmpdat, mod; + int datsta = -1; + int count0 = 0; + int count1 = 0; + + int i, j, k, l; + for (i = 0; i < height; i++) // 行计数 + { + pTmpDat = pBitDat; + int countIdx = 0; + count0 = 0; + count1 = 0; + + for (j = 0, k = 0; (j < widthBytes) && (k < width); j++) // 行内扫描,检测出每段连续0和1的个数 + { + tmpdat = *pTmpDat++; +// if(j+i*widthBytes > 12879) +// { +// qDebug()<> (8 - (width - k )); + } + + //for (mod = 0x80; (mod != 0) && (k < width); k++, mod /= 2) + for (mod = 0x01; (mod != 0) && (k < width); k++, mod *= 2) + { + if ((tmpdat & mod) == 0) + { + if (datsta == 1) + { + count1 |= 0x80000000; + countBuff[countIdx] = count1; + countIdx++; + count1 = 0; + } + datsta = 0; + count0++; + } + else + { + if (datsta == 0) + { + countBuff[countIdx] = count0; + countIdx++; + count0 = 0; + } + datsta = 1; + count1++; + } + } + } + + if (count0 != 0) + { + countBuff[countIdx] = count0; + countIdx++; + count0 = 0; + } + + if (count1 != 0) + { + count1 |= 0x80000000; + countBuff[countIdx] = count1; + countIdx++; + count1 = 0; + } + + + int psta = 0; + int pcount = 0; + unsigned char tgtdat = 0, pmod = 0x20, nums; + + for (l = 0; l < countIdx; l++) // 分析数据,生成压缩数据 + { + if ((countBuff[l] & 0x80000000) != 0) + { + count1 = countBuff[l] & 0xfffffff; + + while (count1 != 0) + { + if (psta == 0) // 当前状态是原始数据 + { + if (pcount != 0) + { + while (count1 != 0 && pcount != 0) + { + tgtdat |= pmod; + pcount--; + count1--; + //pmod /= 2; + pmod *= 2; + } + + if (pcount == 0) // 够一个位图 + { + tgtdat &= 0x3f; + m_prDdat.append(tgtdat); // 添加 + //qDebug()< 64) + { + nums = 64; + } + else + { + nums = count1; + } + + psta = 0x40; + tgtdat = psta; + tgtdat |= (nums & 0x3f); + m_prDdat.append(tgtdat); // 添加 + //qDebug()<= 640) + { + nums = 64; + muti = 10; + psta = 0x80; + } + //else if (count0 > 64) + else if (count0 >= 64) + { + nums = (int)(count0/10); + muti = 10; + psta = 0x80; + } + else + { + nums = count0; + muti = 1; + psta = 0xC0; + } + + tgtdat = psta; + tgtdat |= (nums & 0x3f); + m_prDdat.append(tgtdat); // 添加 + //qDebug()<biWidth + 31) / 32) * 4; + m_rbwDdat.append((char*)pHead,sizeof(BitmapHead)); + + if (m_prDdat.isEmpty() == 1) + { + qDebug() << "pr dat empty"; + return -1; + } + + unsigned char sdat = 0; + int count0,count1,flag; + count0 = count1 = 0; + flag = -1; + + int size = m_prDdat.size(); + for(int i = 0; i < size; i++) + { +// if(i > 3250) +// { +// int a = 0; +// a = 1; +// } + count0 = count1 = 0; + flag = -1; + + sdat = m_prDdat[i]; + + if((sdat & 0xC0) == 0xC0) // 连续0 + { + count0 = sdat & 0x3f; + flag = 0; + } + else + { + if((sdat & 0x40) == 0x40) // 连续1 + { + count1 = sdat & 0x3f; + flag = 1; + } + else if((sdat & 0x80) == 0x80) // 连续10个0 + { + count0 = (sdat & 0x3f ) * 10; + flag = 0; + } + else // 原始数据 + { + //每行扫描时最后一个像素为原始数据时原始数据个数 + int pcount = 6; + int val = arrdat.size() % pHead->biWidth; + int cnt = pHead->biWidth - val; + int cnt1 = abs(pHead->biWidth - (widthBytes-1) * 8); + if(cnt >= cnt1) + { + pcount = 6; + } + else + { + if(cnt > 6) + { + pcount = 6; + } + else + { + pcount = cnt; + } + } + + unsigned char sch = sdat & 0x3f; //够一个位图 + + unsigned char pmod = 0x01; + while (pcount != 0) + { + if((sch & pmod) != 0) // 为1 + { + arrdat.append((char)0x01); + } + else // 为0 + { + arrdat.append((char)0x00); + } + pcount--; + pmod *= 2; + } + + continue; + } + } + + int count = 0; + unsigned char ch = 0; + if(flag == 0) + { + count = count0; + ch = 0; + } + else if(flag == 1) + { + count = count1; + ch = 1; + } + + for(int j = 0; j < count; j++) + { + arrdat.append(ch); + } + } + + int num = 0; + unsigned char abyte = 0; + unsigned int cnt = 0; + for(unsigned int n = 0; n < pHead->biHeight; n++) + { + for(int j = 0; j < widthBytes; j++) + { + abyte = 0; + for(int i = 0; i < 8; i++) + { + int idx = n*pHead->biWidth+j*8+i; + //qDebug()<<"idx"<biWidth) + { + abyte |= ch; + } + else if(cnt == pHead->biWidth) + { + abyte = abyte << (8 - i); + } + else if(cnt >= ((pHead->biWidth/8)*8+8)) + { + abyte = 0; + } + else + { + continue; + } + } + + //if(abyte != 0) + { + //qDebug()< +#include + +#pragma pack(1) //设定为1字节对齐 + +// 位图的调色板 +typedef struct +{ + unsigned char rgbBlue; + unsigned char rgbGreen; + unsigned char rgbRed; + unsigned char rgbReserved; +}__attribute__ ((packed)) BmpRgbQuad; + +// 位图文件头 +typedef struct +{ + unsigned short int identifier; // 类型 一般为 "BM" + unsigned long int fileSize; // 文件大小 + unsigned long int reserved; // 保留 + unsigned long int bitDatOffset; // 位图数据偏移,一般为 0x3E + + unsigned long int biSize; // 位图信息头大小, 一般为 0x28 + unsigned long int biWidth; // 位图宽度,以像素为单位 + unsigned long int biHeight; // 位图高度,以像素为单位 + unsigned short int biPlanes; // 位图的位面数,必须为1 + unsigned short int biBitPerPixel; // 每个像素的位数, =1, 单色位图; =4, 16色; = 8, 256色; = 24 真彩色 + unsigned long int biCompression; // 位图压缩类型, =0, 不压缩(BI_RGB); =1, BI_RLE8; = 2, BI_RLE4; = 3 BI_BITFIELDS; = 4, BI_JPEG; = 5, BI_PNG + unsigned long int biBitmapDatSize;// 位图数据区的大小(字节数), 必须是4的整数倍 + unsigned long int biHResolution; // 水平分辨率, 像素/米 + unsigned long int biVResolution; // 垂直分辨率, 像素/米 + unsigned long int biColors; // 颜色数 + unsigned long int biImpColors; // 重要颜色数 + BmpRgbQuad palette[2]; // 调色板 +}__attribute__ ((packed)) BitmapHead; + +#pragma pack(4) + + +class BWBmp +{ +public: + BWBmp(); + +public: + int LoadBiBmp(QString filename); + int SavePrBmp(QString filename); + int Compress(int dir = 1); + + int LoadPrBmp(QString filename); + int Unpress(); + int SaveBiBmp(QString filename); + + QByteArray getPrBmpDat(); + +private: + + QByteArray m_bwDdat; + QByteArray m_prDdat; + + QByteArray m_rbwDdat; + QString m_fileName; +}; + + + + + + +#endif // BWBMP_H diff --git a/machine/bmp/creatprintbmp.cpp b/machine/bmp/creatprintbmp.cpp new file mode 100644 index 0000000..0c770a8 --- /dev/null +++ b/machine/bmp/creatprintbmp.cpp @@ -0,0 +1,741 @@ +#include "creatprintbmp.h" + +CreatPrintBmp::CreatPrintBmp(QObject *parent) : QObject(parent) +{ + m_savePath.clear(); + m_workState = PAUSE; + m_beginPrintFileIdx = -1; + m_fileBegIdx = -1; + m_fileEndIdx = -1; + m_deleteFileIdx = -1; + m_curFileIdx = -1;//当前生成数据的文件索引 + m_curBmpBlockIdx = -1;//当前生成数据的位图块数索引 + m_mcPrintInfo = NULL; + m_conpressDir = 1; + m_printFileDir.clear(); + m_moveFileIdx = -1;//上下移动打印文件索引 + m_moveDir = 0;//-1,上移 1,下移 +} + +CreatPrintBmp::~CreatPrintBmp() +{ + if(m_mcPrintInfo != NULL) + { + m_mcPrintInfo->clear(); + delete m_mcPrintInfo; + } +} + +int CreatPrintBmp::creatFileListMarker() +{ + if(m_mcPrintInfo->m_loadFileFinishFlag < 0) + { + QString iniName = "MachineNo" + QString::number(m_mcPrintInfo->m_mcNum) + ".ini"; + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + iniName; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + QString dirPath = setting.value("AutoPrintDir/fileDir").toString(); + QDir dir(dirPath); + if(dir.exists()) + { + QStringList filter; + filter << QString("*.plt") << QString("*.PLT") + << QString("*.png") << QString("*.PNG") + << QString("*.bmp") << QString("*.BMP") + << QString("*.jpg") << QString("*.JPG"); + QFileInfoList fileList = dir.entryInfoList(filter, QDir::Files | QDir::NoSymLinks); + + for(int i = 0; i < fileList.size(); i++) + { + if(m_workState == WORK_PAUSE) + { + return -1; + } + + //QCoreApplication::processEvents(QEventLoop::AllEvents); + + QFileInfo fileInfo(fileList[i]); + QString filePath = fileInfo.filePath(); + + if(m_mcPrintInfo->m_filesList.size() > i) + { + //已经生成数据的跳过 + if(m_mcPrintInfo->m_filesList[i].m_creatDataFlag != 1) + { + McFilesInfo curFilesInfo;//当前文件信息 + creatMarkerDat(curFilesInfo,filePath,i); + long long fileTotalLength = (curFilesInfo.m_fileRect.right() - curFilesInfo.m_fileRect.left())/M_IDPMM; + m_mcPrintInfo->m_fileNums = i+1; + m_mcPrintInfo->m_fileTotalLength += fileTotalLength; + m_mcPrintInfo->m_filesList.append(curFilesInfo); + } + } + else + { + McFilesInfo curFilesInfo;//当前文件信息 + creatMarkerDat(curFilesInfo,filePath,i); + long long fileTotalLength = (curFilesInfo.m_fileRect.right() - curFilesInfo.m_fileRect.left())/M_IDPMM; + m_mcPrintInfo->m_fileNums = i+1; + m_mcPrintInfo->m_fileTotalLength += fileTotalLength; + m_mcPrintInfo->m_filesList.append(curFilesInfo); + } + } + m_mcPrintInfo->m_loadFileFinishFlag = 1; + } + } + + QDir apppath(qApp->applicationDirPath()); + QString printPath = apppath.path() + apppath.separator() + PRINTDIR; + QDir printDir(printPath);//总的打印目录 + if(!printDir.exists()) + { + printDir.mkdir(printPath); + } + QString mcFile = printPath + printDir.separator() + PRINTMCDIR + QString::number(m_mcPrintInfo->m_mcNum); + QDir mcDir(mcFile);//对应每台机器打印目录 + if(!mcDir.exists()) + { + mcDir.mkdir(mcFile); + } + + return 0; +} + +void CreatPrintBmp::creatMarkerDat(McFilesInfo &curFilesInfo, QString filePath, int fileIdx) +{ + QFileInfo fileInfo(filePath); + curFilesInfo.m_marker.Initialize(); + + if(fileInfo.suffix().toUpper() == "PLT") + { + ImportHPGL importHPGL; + curFilesInfo.m_fileType = TYPE_FILE; + + //判断是否为加密文件 + if (importHPGL.IsSecretFile(filePath) == true) + { + // 文件路径 + QString strSecretFile = m_printFileDir + QString::number(fileIdx+1) ; + + QDir fileDir(strSecretFile);//对应每台机器的每个文件打印目录 + if(!fileDir.exists()) + { + fileDir.mkdir(strSecretFile); + } + strSecretFile = strSecretFile + fileDir.separator() + "Secret.plt"; + //qDebug()<<"strSecretFile"< 0)//有位图 + { + painter.drawPixmap(bitmapInfo.m_ptAbPostLU.x(),bitmapInfo.m_ptAbPostLU.y(),bitmapInfo.m_pBitmap); + } + painter.end(); + return pic; +} + +int CreatPrintBmp::creatFileListDatAndSend(int idx) +{ + if(idx >= m_mcPrintInfo->m_filesList.size()) + { + return 1; + } + + McFilesInfo curFilesInfo; + + if(m_workState == WORK_PAUSE) + { + return -1; + } + + curFilesInfo = m_mcPrintInfo->m_filesList[idx]; + QString filePath = m_printFileDir + QString::number(idx+1); + QDir fileDir(filePath);//对应每台机器的每个文件打印目录 + if(!fileDir.exists()) + { + fileDir.mkdir(filePath); + } + filePath = filePath + fileDir.separator(); + + if(curFilesInfo.m_creatDataFlag < 0) + { + creatMarkerDat(curFilesInfo,m_mcPrintInfo->m_filesList[idx].m_filePath,idx); + m_mcPrintInfo->m_filesList[idx] = curFilesInfo; + } + + QPicture pic; + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(Qt::black)); + + int oft = 0;//起始打印位置的偏移 + if(curFilesInfo.m_fileType == TYPE_FILE) + { + //画笔宽度不为1时重画 + if(PENWIDTH != 1) + { + pic = getPicture(curFilesInfo.m_marker,PENWIDTH); + } + else + { + pic = m_mcPrintInfo->m_filesList[idx].m_pic; + } + + oft = (int)(m_mcPrintInfo->m_filesList[idx].m_startPoint*MMPIXELY); + //将picture保存为多个宽度为PIXMAPWIDTH像素的bmp + m_mcPrintInfo->m_totalNums = (pic.width() - oft) / PIXMAPWIDTH; + int lwidth = (pic.width() - oft) % (PIXMAPWIDTH); + if(lwidth != 0) + { + m_mcPrintInfo->m_totalNums += 1; + } + } + else if(curFilesInfo.m_fileType == TYPE_IMAGE) + { + //将图片画在picture上 + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPixmap(0,0,m_mcPrintInfo->m_filesList[idx].m_pixmap); + painter.end(); + + //将pixmap保存为多个宽度为PIXMAPWIDTH像素的bmp + m_mcPrintInfo->m_totalNums = curFilesInfo.m_pixmap.width() / PIXMAPWIDTH; + int lwidth = curFilesInfo.m_pixmap.width() % PIXMAPWIDTH; + if(lwidth != 0) + { + m_mcPrintInfo->m_totalNums += 1; + } + } + m_mcPrintInfo->m_filesList[idx].m_pic = pic; + m_mcPrintInfo->m_filesList[idx].m_totalBlocks = (pic.width() - oft)/ PIXMAPWIDTH; + + //发送文件列表数据 + emit siSendFileListDatToMc(idx); + return 0; +} + +int CreatPrintBmp::creatBmpBlockDatAndSend(int idx) +{ + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(Qt::black)); + + int nextNum = idx / m_mcPrintInfo->m_filesList[m_curFileIdx].m_totalBlocks; + if((idx % m_mcPrintInfo->m_filesList[m_curFileIdx].m_totalBlocks) == 0) + { + idx = 0; + } + + QPicture pic = m_mcPrintInfo->m_filesList[m_curFileIdx].m_pic; + int oft = (int)(m_mcPrintInfo->m_filesList[m_curFileIdx].m_startPoint*MMPIXELY); + + //将picture保存为多个宽度为PIXMAPWIDTH像素的bmp + int num = (pic.width() - oft) / PIXMAPWIDTH; + int lwidth = (pic.width() - oft) % PIXMAPWIDTH; + int height = pic.height(); + int offset = 0 - idx * PIXMAPWIDTH + oft;//将picture画在bmp上每次的偏移量,bmp的最大尺寸为u16 + + if(lwidth != 0) + { + num += 1; + } + + QBitmap *pixmap = new QBitmap(PIXMAPWIDTH,height); + QPainter *pixPainter = new QPainter(); + pixPainter->begin(pixmap); + pixPainter->setPen(pen); + + QString filePath = m_printFileDir + QString::number(m_curFileIdx+1); + QDir fileDir(filePath);//对应每台机器的每个文件打印目录 + if(!fileDir.exists()) + { + fileDir.mkdir(filePath); + } + filePath = filePath + fileDir.separator(); + + pixmap->fill(Qt::white);//用白色填充 + pixPainter->drawPicture(offset,0,pic); + + QString path = filePath+QString::number(idx+nextNum*m_mcPrintInfo->m_filesList[m_curFileIdx].m_totalBlocks+1)+".bmp"; + bool bls = pixmap->save(path); + while(bls == false) + { + bls = pixmap->save(path); + qDebug()<<"pixmap save failed"; + } + + //压缩位图 + BWBmp bwBmp; + int rslt; + + rslt = bwBmp.LoadBiBmp(path); + if (rslt != 0) + { + qDebug() << "open file error" << path; + return -1; + } + rslt = bwBmp.Compress(m_conpressDir); + if (rslt != 0) + { + qDebug() << "Compress error"; + return -1; + } + + rslt = bwBmp.SavePrBmp(path+".prbmp"); + if (rslt != 0) + { + qDebug() << "save prbmp error"; + return -1; + } + QByteArray dat = bwBmp.getPrBmpDat(); + + //发送文件 + BmpDatInfo bmpInfo; + memset(&bmpInfo,0,sizeof(BmpDatInfo)); + bmpInfo.blkIdx = idx; + bmpInfo.biWidth = pixmap->width(); + bmpInfo.biHeight = pixmap->height(); + bmpInfo.begPosY = idx * pixmap->width(); + bmpInfo.endPosY = (idx+1) * pixmap->width(); + if(m_conpressDir == -1) + { + bmpInfo.compDir = 0; + } + else + { + bmpInfo.compDir = 1; + } + //qDebug()<<"dat.size()"<m_sendedlNums++; + + pixPainter->end(); + + bool bla = pixPainter->isActive(); + while(bla == true) + { + bla = pixPainter->isActive(); + qDebug()<<"pixPainter isActive"; + } + + delete pixmap; + delete pixPainter; + return 0; +} + +void CreatPrintBmp::slotCreatBmp() +{ +#if(1) + int val = creatFileListMarker(); + if(val < 0) + { + return; + } + + val = creatFileListDatAndSend(m_curFileIdx); + if(val < 0) + { + return; + } +#else + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(Qt::black)); + + //将picture保存为多个宽度为PIXMAPWIDTH像素的bmp + int num = m_picture.width() / PIXMAPWIDTH; + int lwidth = m_picture.width() % PIXMAPWIDTH; + int height = m_picture.height(); + int offset = 0; + + if(lwidth != 0) + { + num += 1; + } + + QBitmap *pixmap = new QBitmap(PIXMAPWIDTH,height); + QPainter *pixPainter = new QPainter(); + pixPainter->begin(pixmap); + pixPainter->setPen(pen); + + for(int i = 0 ; i < num; i++) + { + pixmap->fill(Qt::white);//用白色填充 + pixPainter->drawPicture(offset,0,m_picture); + offset -= PIXMAPWIDTH; + + QString path = m_savePath+QString::number(i+1)+".bmp"; + bool bls = pixmap->save(path); + while(bls == false) + { + bls = pixmap->save(path); + qDebug()<<"pixmap save failed"; + } + + //压缩位图 + BWBmp bwBmp; + int rslt; + + rslt = bwBmp.LoadBiBmp(path); + if (rslt != 0) + { + qDebug() << "open file error" << path; + break; + } + rslt = bwBmp.Compress(); + if (rslt != 0) + { + qDebug() << "Compress error"; + break; + } + + rslt = bwBmp.SavePrBmp(path+".prbmp"); + if (rslt != 0) + { + qDebug() << "save prbmp error"; + break; + } + QByteArray dat = bwBmp.getPrBmpDat(); + siCreatOneBmpFinished((unsigned char*)dat.data(),dat.size()); + } + + pixPainter->end(); + + bool bla = pixPainter->isActive(); + while(bla == true) + { + bla = pixPainter->isActive(); + qDebug()<<"pixPainter isActive"; + } + + delete pixmap; + delete pixPainter; +#endif +} + +void CreatPrintBmp::slotCreatNextBmpBlockDat() +{ + //非正在打印的文件,正在发送文件时的删除操作 + if(m_deleteFileIdx != m_curFileIdx && m_deleteFileIdx != -1) + { + int length = (m_mcPrintInfo->m_filesList[m_deleteFileIdx].m_fileRect.right() - m_mcPrintInfo->m_filesList[m_deleteFileIdx].m_fileRect.left())/M_IDPMM; + m_mcPrintInfo->m_fileTotalLength -= length; + m_mcPrintInfo->m_filesList[m_deleteFileIdx].clear(); + m_mcPrintInfo->m_filesList.removeAt(m_deleteFileIdx); + QString mcFile = m_printFileDir + QString::number(m_deleteFileIdx+1); + QDir fileDir(mcFile); + if(fileDir.exists())//理论上无此条件 + { + //删除位图文件夹 + QFileInfoList fileList = fileDir.entryInfoList(QDir::Files); + for(int i = 0; i < fileList.size(); i++) + { + QString fileStr = fileList[i].filePath(); + QFile::remove(fileStr); + } + fileDir.rmdir(mcFile); + } + + if(m_deleteFileIdx < m_curFileIdx)//理论上无此条件 + { + QString oldName = m_printFileDir + QString::number(m_curFileIdx+1); + QDir dir(oldName); + m_curFileIdx--; + QString newName = m_printFileDir + QString::number(m_curFileIdx+1); + dir.rename(oldName,newName); + } + + m_mcPrintInfo->m_fileNums = m_mcPrintInfo->m_filesList.size(); + m_deleteFileIdx = -1; + emit siDeleteFileFinish(); + } + + //非正在打印的文件,正在发送文件时的上下移操作 + if(m_moveFileIdx != m_curFileIdx && m_moveFileIdx != -1 && m_moveDir != 0) + { + //交换列表 + McFilesInfo info = m_mcPrintInfo->m_filesList[m_moveFileIdx]; + McFilesInfo cInfo; + cInfo = m_mcPrintInfo->m_filesList[m_moveFileIdx+m_moveDir]; + m_mcPrintInfo->m_filesList[m_moveFileIdx+m_moveDir] = info; + m_mcPrintInfo->m_filesList[m_moveFileIdx] = cInfo; + + //更换位图文件夹的名称 + //判断当前交换的文件夹是否存在 + QString mcFile = m_printFileDir + QString::number(m_moveFileIdx+1); + QDir fileDir(mcFile); + if(fileDir.exists())//理论上无此条件 + { + //对当前选中文件夹重命名 + QString oldName = mcFile; + QString newName = mcFile.left(mcFile.size()-1); + fileDir.rename(oldName,newName); + + int cRow = m_moveFileIdx + m_moveDir; + QString mcFile1 = m_printFileDir + QString::number(cRow+1); + QDir fileDir1(mcFile1); + + //对要交换的文件夹重命名 + oldName = mcFile1; + newName = mcFile; + fileDir1.rename(oldName,newName); + + //再对选中的文件夹重命名 + QString mcFile2 = mcFile.left(mcFile.size()-1); + QDir fileDir2(mcFile1); + oldName = mcFile2; + newName = mcFile1; + fileDir2.rename(oldName,newName); + } + + m_moveFileIdx = -1; + m_moveDir = 0; + } + + m_curBmpBlockIdx++;//一个文件可分为若干个位图块,位图块索引++ + if(m_curBmpBlockIdx < 0) + { + m_curBmpBlockIdx = 0; + } + + if(m_curBmpBlockIdx >= m_mcPrintInfo->m_filesList[m_curFileIdx].m_totalBlocks * m_mcPrintInfo->m_filesList[m_curFileIdx].m_printNum) + { + m_curFileIdx++;//文件索引++ + creatFileListDatAndSend(m_curFileIdx); + m_curBmpBlockIdx = -1; + return; + } + + creatBmpBlockDatAndSend(m_curBmpBlockIdx); + m_conpressDir *= -1; +} + +void CreatPrintBmp::setPicture(QPicture pic) +{ + m_picture = pic; +} + +void CreatPrintBmp::setPicture(QBitmap bitmap) +{ + //将图片画在picture上 + QPicture pic; + QPen pen; + pen.setWidth(1);//设置笔号 + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + painter.drawPixmap(0,0,bitmap); + painter.end(); + m_picture = pic; +} + +void CreatPrintBmp::setSavePath(QString path) +{ + m_savePath.clear(); + m_savePath = path; +} + +QString CreatPrintBmp::getSavePath() +{ + return m_savePath; +} + +void CreatPrintBmp::setMcPrintInfo(int fileIdx, McPrintInfo *printInfo) +{ + m_mcPrintInfo = printInfo; + + if(fileIdx < 0) + { + m_fileBegIdx = 0; + } + else + { + m_fileBegIdx = fileIdx; + } + + //自动打印 + int autoPrint = 1; + + if(autoPrint == 1) + { + m_fileEndIdx = m_mcPrintInfo->m_filesList.size(); + } + else + { + m_fileEndIdx = m_fileBegIdx + 1; + } + + m_curFileIdx = m_fileBegIdx; + + QDir apppath(qApp->applicationDirPath()); + QString printPath = apppath.path() + apppath.separator() + PRINTDIR; + QString mcFile = printPath + apppath.separator() + PRINTMCDIR + QString::number(m_mcPrintInfo->m_mcNum); + m_printFileDir = mcFile + apppath.separator() + PRINTFILEDIR; +} + +void CreatPrintBmp::setDeleteFile(int fileIdx) +{ + if(fileIdx == m_curFileIdx) + { + return; + } + m_deleteFileIdx = fileIdx; + //空闲时的删除文件操作 + if(m_mcPrintInfo->m_mcWorkState == NotBusy) + { + int length = (m_mcPrintInfo->m_filesList[m_deleteFileIdx].m_fileRect.right() - m_mcPrintInfo->m_filesList[m_deleteFileIdx].m_fileRect.left())/M_IDPMM; + m_mcPrintInfo->m_fileTotalLength -= length; + m_mcPrintInfo->m_filesList[m_deleteFileIdx].clear(); + m_mcPrintInfo->m_filesList.removeAt(m_deleteFileIdx); + QString mcFile = m_printFileDir + QString::number(m_deleteFileIdx+1); + QDir fileDir(mcFile); + if(fileDir.exists()) + { + //删除位图文件夹 + QFileInfoList fileList = fileDir.entryInfoList(QDir::Files); + for(int i = 0; i < fileList.size(); i++) + { + QString fileStr = fileList[i].filePath(); + QFile::remove(fileStr); + } + fileDir.rmdir(mcFile); + } + + m_mcPrintInfo->m_fileNums = m_mcPrintInfo->m_filesList.size(); + m_deleteFileIdx = -1; + emit siDeleteFileFinish(); + } +} + +void CreatPrintBmp::setMoveFile(int fileIdx, int dir) +{ + if(fileIdx == m_curFileIdx) + { + return; + } + m_moveFileIdx = fileIdx;//上下移动打印文件索引 + m_moveDir = dir;//-1,上移 1,下移 + + //空闲时的移动文件操作 + if(m_mcPrintInfo->m_mcWorkState == NotBusy) + { + //交换列表 + McFilesInfo info = m_mcPrintInfo->m_filesList[fileIdx]; + McFilesInfo cInfo; + if(dir == -1) + { + cInfo = m_mcPrintInfo->m_filesList[fileIdx-1]; + m_mcPrintInfo->m_filesList[fileIdx-1] = info; + } + else + { + cInfo = m_mcPrintInfo->m_filesList[fileIdx+1]; + m_mcPrintInfo->m_filesList[fileIdx+1] = info; + } + + m_mcPrintInfo->m_filesList[fileIdx] = cInfo; + + m_moveFileIdx = -1;//上下移动打印文件索引 + m_moveDir = 0;//-1,上移 1,下移 + } +} diff --git a/machine/bmp/creatprintbmp.h b/machine/bmp/creatprintbmp.h new file mode 100644 index 0000000..33e86fd --- /dev/null +++ b/machine/bmp/creatprintbmp.h @@ -0,0 +1,94 @@ +#ifndef CREATPRINTBMP_H +#define CREATPRINTBMP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bwbmp.h" +#include "machine/printinfo/mcfiles.h" +#include "datafile/hpgl/importhpgl.h" + +#define TYPE_FILE 0 +#define TYPE_IMAGE 1 +#define PIXMAPWIDTH 1200 +#define PENWIDTH 5 + +#define START 1 +#define PAUSE 0 + +#define PRINTDIR "print" +#define PRINTMCDIR "mc" +#define PRINTFILEDIR "file" + +typedef struct +{ + u32 blkIdx; // 当前位图块号(位图分块后的编号) + u32 biWidth; // 本块位图有效宽度,以像素为单位 + u32 biHeight; // 本块位图有效高度,以像素为单位 + u32 begPosY; // 本块起始位置(像素单位) + u32 endPosY; // 本块结束位置(像素单位) + u8 compType; // 本块位图压缩类型, =0, 不压缩; =1, 按字节压缩; + u8 compDir; // 本块位图压缩方向, =0, 从上到下; =1, 从下到上;(喷墨方向) +}__attribute__ ((packed)) BmpDatInfo; + +class CreatPrintBmp : public QObject +{ + Q_OBJECT +public: + explicit CreatPrintBmp(QObject *parent = NULL); + virtual ~CreatPrintBmp(); + +private: + QPicture m_picture;//绘图路径-线段 + QString m_savePath; + int m_workState; + int m_beginPrintFileIdx;//开始打印文件索引 + int m_deleteFileIdx;//删除打印文件索引 + McPrintInfo *m_mcPrintInfo;//机器信息 + int m_fileBegIdx; + int m_fileEndIdx; + int m_curFileIdx;//当前生成数据的文件索引 + int m_curBmpBlockIdx;//当前生成数据的位图块数索引 + int m_conpressDir;//压缩方向 + QString m_printFileDir;//打印文件目录 + + int m_moveFileIdx;//上下移动打印文件索引 + s16 m_moveDir;//-1,上移 1,下移 + +private: + int creatFileListMarker();//加载文件列表marker数据 + void creatMarkerDat(McFilesInfo &curFilesInfo, QString filePath, int fileIdx);//创建Marker数据 + QPicture getPicture(Marker marker,int penWidth = 1); + + int creatFileListDatAndSend(int idx);//创建文件列表数据并发送 + int creatBmpBlockDatAndSend(int idx);//创建位图块数据并发送 + +public: + void setPicture(QPicture pic); + void setPicture(QBitmap bitmap); + void setSavePath(QString path); + QString getSavePath(); + void setMcPrintInfo(int fileIdx,McPrintInfo *printInfo);//设置机器信息 + void setDeleteFile(int fileIdx);//删除文件 + void setMoveFile(int fileIdx, int dir = -1);//上下移动文件 + +signals: + void siCreatOneBmpFinished(int mcIdx,unsigned char *dat,int datSize); + void siSendFileListDatToMc(int idx); + void siSendDatToMc(QByteArray dat, BmpDatInfo bmpInfo); + void siDeleteFileFinish();//删除文件完成 + +public slots: + void slotCreatBmp(); + void slotCreatNextBmpBlockDat();//创建下一个位图块数据 + +}; + +#endif // CREATPRINTBMP_H diff --git a/machine/comm/comm.cpp b/machine/comm/comm.cpp new file mode 100644 index 0000000..97917cc --- /dev/null +++ b/machine/comm/comm.cpp @@ -0,0 +1,438 @@ +//------------------------------------------------------------------------------- +// File Name: comm.cpp +// Brief: +// Version: 1.0.0 +// Create Date: 2017/05/08 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2017, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2017/05/08 +//------------------------------------------------------------------------------- + +#define _IN_COMM_CPP + +#include "comm.h" +#include "crc16.h" + + +//-------------------------------------------------------------------------------------------------- + +// 读空缓冲区 +void readBuffEmpty(DataExFuns * funs) +{ + int rslt, len; + u8 temp; + + len = funs->getRsvLen(); + + while (len > 0) + { + rslt = funs->getCommData(&temp, 1); + if (rslt != 1) + { + rslt = 0; + break; + } + len--; + } +} + +//-------------------------------------------------------------------------------------------------- +// 功能: 从通讯口接收缓冲区中得到一个数据包, 如果有附加数据,包括附加数据 +// 参数: pPacket, 数据包指针 +// 返回: >=0, 成功取得一个数据包,包括定长数据包和可变长度数据包,返回值为数据包长度 +// -1, 参数错误 +// -2, CRC错误 +// -3, 数据不足 +// -4, 没有找到同步序列 +// -5,等待接收数据超时 +// -6, 数据包参数错误 +// -7, 附加数据CRC错误 +// -8, 发生未知错误 + +// 结果: 如果正确取得数据包,或通讯口没有命令, 循环队列尾指针回向后移动 + +int getANormalPacket(DataExFuns * funs, DataPacket * pPacket) +{ + int rslt, len; + int i; + int phase; + int status; + int exlen; + static int rdstatus = 0; + static u8 odBuf[LEN_NORMAL_PACKET]; + + u8 temp; + u8 rdBuf[LEN_NORMAL_PACKET]; + DataPacket * pDat; + + u8 getBuf[LEN_NORMAL_PACKET-DP_SYNC_LEN]; + int getBuflen; + int getIdx; + + u8 tmpBuf[LEN_NORMAL_PACKET-DP_SYNC_LEN]; + int tmpBuflen; + + if (funs == NULL || pPacket == NULL) + { + return -1; + } + + rslt = 0; + i = 0; // 扫描字节计数器 + getBuflen = 0; + getIdx = 0; + tmpBuflen = 0; + pDat = (DataPacket *)rdBuf; + + if (rdstatus == 0) + { + do + { + len = funs->getRsvLen(); // 得到接收长度 + len += getBuflen; // 加上已经获取的长度 + + if (len < LEN_NORMAL_PACKET) + { + rslt = -3; + break; // 没有足够数据 + } + + phase = 0; + status = 0; + rslt = 0; + + // 从接收缓冲区中找数据包 + while(((len + phase) >= LEN_NORMAL_PACKET) && (phase < LEN_NORMAL_PACKET)) + { + if (getBuflen == 0) + { + if (phase == 0 && i > MAX_ONCE_SCAN) + { + rslt = -4; + break; // 查找同步序列超出最大单次扫描字节数 + } + + rslt = funs->getCommData(&temp, 1); + if (rslt != 1) + { + printf("error at GetCommData rslt\r\n"); + rslt = -8; + break; + } + rslt = 0; + i++; // 扫描字数增加 + } + else + { + temp = getBuf[getIdx]; + getIdx++; + getBuflen--; + } + + len--; // 剩余长度减小 + + pDat->buff.normal[phase] = temp; + if (phase < DP_SYNC_LEN) // 识别同步序列 + { + tmpBuflen = 0; + + if (phase == 0) + { + if (temp == FLDP_SYNC[0]) + { + status = 1; + } + else if (temp == VLDP_SYNC[0]) + { + status = 2; + } + else + { + status = 0; + phase = 0; + rslt = 0; // 非同步序列 + break; + } + } + else + { + if (status == 1) + { + if (temp != FLDP_SYNC[phase]) + { + status = 0; + phase = 0; + rslt = 0; + break; + } + } + else if (status == 2) + { + if (temp != VLDP_SYNC[phase]) + { + status = 0; + phase = 0; + rslt = 0; + break; + } + } + else + { + printf("error status in GetANormalPacket\r\n"); + rslt = -8; + break; + } + } + } + else + { + tmpBuf[tmpBuflen] = temp; + tmpBuflen++; + } + + phase++; + } + + if (rslt != 0) + { + break; + } + + if (phase >= LEN_NORMAL_PACKET) // 得到数据包 + { + u16 crc; + crc = calcCrc16(pDat->normal.content, DP_CONT_LEN); + if (crc == pDat->normal.crc) + { + // 得到正确数据包 + memcpy(pPacket, pDat, LEN_NORMAL_PACKET); + + // printf("GetANormalPacket ok\r\n"); + rslt = LEN_NORMAL_PACKET; + break; + } + else + { + // CRC 不正确 + printf("crc error in GetANormalPacket\r\n"); + // 拷贝需要再判断的数据 + if (tmpBuflen != 0) + { + memcpy(getBuf, tmpBuf, tmpBuflen); + } + getBuflen = tmpBuflen; + getIdx = 0; + // continue; + } + } + else + { + // 没有找到同步序列的情况 + getBuflen = 0; + getIdx = 0; + // continue; + } + }while(1); + } + + if (rdstatus == 1) + { + memcpy(pPacket, odBuf, LEN_NORMAL_PACKET); + rslt = LEN_NORMAL_PACKET; + } + + // 附加数据 + if (rslt == LEN_NORMAL_PACKET) + { + if (memcmp(pPacket->normal.sync, VLDP_SYNC, DP_SYNC_LEN) == 0) // 是可变长度数据包 + { + exlen = pPacket->vldp.exlen; + if (exlen > MAX_EXDP_LEN) + { + printf("data exlen error, len=%d\r\n", exlen); + return -6; // 数据包参数错误 + } + + memset(pPacket->buff.exData, 0, MAX_EXDP_LEN); + + i = 0; + status = 0; // 作为历史计数器 + // 读取附加数据 + do + { + rslt = funs->getCommData(pPacket->buff.exData, exlen); + if (rslt == exlen) + { + u16 crc; + // 校验CRC + crc = calcCrc16(pPacket->buff.exData, exlen); + if (crc == pPacket->vldp.excrc) + { +// printf("get exdata ok\r\n"); + rslt = exlen+LEN_NORMAL_PACKET; + } + else + { + printf("crc error at get exdata\r\n"); + rslt = -7; // CRC错误 + } + rdstatus = 0; + break; // 得到数据 + } + else if (rslt == 0) + { + memcpy(odBuf, pPacket, LEN_NORMAL_PACKET); + rdstatus = 1; + rslt = -3; + break; + /* + // 数据不足 + if (funs->delay != NULL) + { + funs->delay(1); // 延时等待 + } + len = funs->getRsvLen(); // 得到接收数据长度 + qDebug()<<"getRsvLen"< GTEX_TIME_OUT) // 如果无变化计数器值大于超时值 + { + qDebug()<<"call GetCommData timeout"; + rslt = -5; + break; + } + } + */ + } + else + { + qDebug()<<"error after call GetCommData"; + break; + } + }while(1); + + } + } + return rslt; +} + +//-------------------------------------------------------------------------------------------------- + +// 功能: 添加数据到发送队列中, 通过通讯口发送数据 +// 参数: pPacket, 需要发送的数据,已经正确存放在了相应字段。 +// 结果: +// 0, 可以发送, 添加到了发送数据队列中 +// -1, 参数错误 +// -2,发送错误 +// 1, 队列已满, 不能发送 +int sendAPacket(DataExFuns * funs, DataPacket * pPacket) +{ + int rslt; + int freelen, sendlen; + + if (pPacket == NULL) + { + return -1; + } + + if (memcmp(pPacket->normal.sync, FLDP_SYNC, DP_SYNC_LEN) == 0) + { + sendlen = LEN_NORMAL_PACKET; + } + else if (memcmp(pPacket->normal.sync, VLDP_SYNC, DP_SYNC_LEN) == 0) + { + sendlen = LEN_NORMAL_PACKET + pPacket->vldp.exlen; + } + else + { + printf("para err, not a corrected packet\r\n"); + return -1; + } + + freelen = funs->getTrsFreeLen(); + + if (freelen < sendlen) + { +// printf("buff is full in SendAPacket\r\n"); + return 1; + } + + rslt = funs->sendCommData(pPacket->datbuff, sendlen); + if (rslt != sendlen) + { + printf("error at call SendCommData, rslt=%d\r\n", rslt); + return -2; + } + + return 0; +} + +//-------------------------------------------------------------------------------------------------- + +// 功能: 打包一个固定长度数据包 +// 参数: +// pPacket, 需要打包的数据包,其中除了sync和crc的部分已经就绪 +// 结果: +// 0, 打包好数据 +// -1, 参数错误 + +int packetAFLDP(DataPacket * pPacket) +{ + if (pPacket == NULL) + { + return -1; + } + + memcpy(pPacket->normal.sync, FLDP_SYNC, DP_SYNC_LEN); + pPacket->normal.crc = calcCrc16(pPacket->normal.content, DP_CONT_LEN); + + return 0; +} + +//-------------------------------------------------------------------------------------------------- + +// 功能: 打包一个可变长度数据包 +// 参数: pPacket, 需要打包的数据包,需要填充其中的 SYNC EXLEN EXCRC 和 EXDAT 等部分 +// pExdat, 附加数据,可以为空 +// exlen,附加数据长度,可以为0 +// 结果: +// 0, 打包好数据 +// -1, 参数错误 +// -2, + +int packetAVLDP(DataPacket * pPacket, u8 * pExdat, u16 exlen) +{ + if (pPacket == NULL) + { + return -1; + } + + if (pExdat == NULL) + { + exlen = 0; + } + + memcpy(pPacket->vldp.sync, VLDP_SYNC, DP_SYNC_LEN); + pPacket->vldp.exlen = exlen; + pPacket->vldp.excrc = calcCrc16(pExdat, exlen); + pPacket->vldp.crc = calcCrc16(pPacket->normal.content, DP_CONT_LEN); + if (exlen != 0) + { + memcpy(pPacket->vldp.exData, pExdat, exlen); + } + return 0; +} + +//-------------------------------------------------------------------------------------------------- + + diff --git a/machine/comm/comm.h b/machine/comm/comm.h new file mode 100644 index 0000000..1925382 --- /dev/null +++ b/machine/comm/comm.h @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------- +// File Name: comm.h +// Brief: +// Version: 1.0.0 +// Create Date: 2017/05/08 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2017, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2017/05/08 +//------------------------------------------------------------------------------- + +#ifndef __COMM_H__ +#define __COMM_H__ + +#include "typedef.h" +#include +#include +#include +//------------------------------------------------------------------------ + +// 通讯数据包定义 + +//------------------------------------ +/* +一、数据包格式 + + 1. 固定长度数据包格式 + + |-------------------------------------------------------------------|-----------| + | 数据识别序列 | 数据内容 | 校验字 | + |-------------------------------------------------------------------|-----------| + | B0 B1 B2 B3 | B4 B5 | B6 B7 B8 B9 B10 B11 B12 B13 | B14 B15 | + |-------------------------------------------------------------------|-----------| + | 固定序列如下 | | 参数,不同命令定义不同 | B4--B13的 | + | | 数据包ID | 具体定义参考命令详细说明 | | + | 'F','L','D','P' | | | 16位CRC | + |-------------------------------------------------------------------|-----------| + + 2. 可变长度数据包格式 + + |---------------------------------------------------------------------------|-----------|---------------- + | 数据识别序列 | 数据内容 | 校验字 | 附加数据 | + |---------------------------------------------------------------------------|-----------|---------------| + | B0 B1 B2 B3 | B4 B5 | B6 B7 | B8 B9 | B10 B11 B12 B13 | B14 B15 | B16--Bn | + |---------------------------------------------------------------------------|-----------|---------------| + | 固定序列如下 | | 附加 | 附加 | 参数,不同命令 | B4--B13的 | 数据内容 | + | | 数据包ID | 数据 | 数据 | 定义不同,定义 | | | + | 'V','L','D','P' | | 长度 | 校验字 | 参考命令详细说明 | 16位CRC | | + |---------------------------------------------------------------------------|-----------|---------------| + + 附加数据长度取值范围为 0--1024 +*/ + +//------------------------------------ + +#define DP_SYNC_LEN 4 // 数据识别序列长度 +#define DP_CONT_LEN 10 // 数据内容长度 +#define DP_CRC_LEN 2 // 校验字长度 +#define MAX_EXDP_LEN 1024 // 最大附加数据长度 + +#define LEN_NORMAL_PACKET (DP_SYNC_LEN+DP_CONT_LEN+DP_CRC_LEN) + +#define MAX_INDP_PARA 8 + +#ifdef _IN_COMM_CPP + +const u8 FLDP_SYNC[DP_SYNC_LEN] = +{ + 'F','L','D','P', +}; + +const u8 VLDP_SYNC[DP_SYNC_LEN] = +{ + 'V','L','D','P', +}; + +#else + +extern const u8 FLDP_SYNC[DP_SYNC_LEN]; +extern const u8 VLDP_SYNC[DP_SYNC_LEN]; + +#endif + +//----------------------------------------------------------------------- + +typedef union +{ + u8 datbuff[LEN_NORMAL_PACKET+MAX_EXDP_LEN]; // dat buff 方式 + + struct + { + u8 normal[LEN_NORMAL_PACKET]; + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) buff; // buff方式 + + struct + { + u8 sync[DP_SYNC_LEN]; + u8 content[DP_CONT_LEN]; + u16 crc; + } __attribute__ ((packed)) normal; // 通用方式 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmd; + u8 para[8]; + u16 crc; + } __attribute__ ((packed)) fldp; // fldp方式 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmd; + u16 exlen; + u16 excrc; + u8 para[4]; + u16 crc; + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) vldp; // vldp方式 + +} DataPacket; + +//----------------------------------------------------------------------- + +typedef struct +{ + int (*sendCommData)(u8 *, int); + int (*getCommData)(u8 *, int); + int (*getRsvLen)(void); + int (*getTrsFreeLen)(void); + void (*delay)(u32); +} DataExFuns; + + +//----------------------------------------------------------------------- + +// 读空缓冲区 +void readBuffEmpty(DataExFuns * funs); + + +//----------------------------------------------------------------------- + +// 功能: 从通讯口接收缓冲区中得到一个数据包, +// 只能取得普通数据包结构. 如果数据包还有附加数据, 那么需要用 GetExCommData 函数取得 +// 参数: pPacket, 数据包指针 +// 返回: >=0, 成功取得一个数据包,包括定长数据包和可变长度数据包,返回值为数据包长度 +// -1, 参数错误 +// -2, CRC错误 +// -3, 数据不足 +// -4, 没有找到同步序列 +// -5,等待接收数据超时 +// -6, 数据包参数错误 +// -7, 附加数据CRC错误 +// -8, 发生未知错误 + +// 结果: 如果正确取得数据包,或通讯口没有命令, 循环队列尾指针回向后移动 + +#define MAX_ONCE_SCAN (LEN_NORMAL_PACKET*10) // 一次扫描最大字节数 +#define GTEX_TIME_OUT 100 // 得到数据包超时时间,单位是ms + +int getANormalPacket(DataExFuns * funs, DataPacket * pPacket); + +//-------------------------------------------------------------------------------------------------- + +// 功能: 添加数据到发送队列中, 通过通讯口发送数据 +// 参数: pPacket, 需要发送的数据,已经正确存放在了相应字段。 +// 结果: +// 0, 可以发送, 添加到了发送数据队列中 +// -1, 参数错误 +// -2,发送错误 +// 1, 队列已满, 不能发送 +int sendAPacket(DataExFuns * funs, DataPacket * pPacket); + +//-------------------------------------------------------------------------------------------------- + +// 功能: 打包一个固定长度数据包 +// 参数: +// pPacket, 需要打包的数据包,其中除了sync和crc的部分已经就绪 +// 结果: +// 0, 打包好数据 +// -1, 参数错误 + +int packetAFLDP(DataPacket * pPacket); + +//-------------------------------------------------------------------------------------------------- + +// 功能: 打包一个可变长度数据包 +// 参数: pPacket, 需要打包的数据包,需要填充其中的 SYNC EXLEN EXCRC 和 EXDAT 等部分 +// pExdat, 附加数据,可以为空 +// exlen,附加数据长度,可以为0 +// 结果: +// 0, 打包好数据 +// -1, 参数错误 +// -2, + +int packetAVLDP(DataPacket * pPacket, u8 * pExdat, u16 exlen); + +//-------------------------------------------------------------------------------------------------- + + +#endif diff --git a/machine/comm/crc16.cpp b/machine/comm/crc16.cpp new file mode 100644 index 0000000..8fbf1f7 --- /dev/null +++ b/machine/comm/crc16.cpp @@ -0,0 +1,159 @@ + +//------------------------------------------------------------------------------- +// File Name: crc16.cpp +// Brief: +// Version: 1.0.0 +// Create Date: 2017/05/08 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2017, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2017/05/08 +//------------------------------------------------------------------------------- + + +#include "crc16.h" + +//------------------------------------------------------------------------------- + +#ifdef USE_CRC_TABLE + +// 16 位 crc 列表 +u16 CRC16_LIST[256] = +{ + 0x0000, 0x3096, 0x612C, 0x51BA, 0xC419, 0xF48F, 0xA535, 0x95A3, + 0x8832, 0xB8A4, 0xE91E, 0xD988, 0x4C2B, 0x7CBD, 0x2D07, 0x1D91, + 0x1064, 0x20F2, 0x7148, 0x41DE, 0xD47D, 0xE4EB, 0xB551, 0x85C7, + 0x9856, 0xA8C0, 0xF97A, 0xC9EC, 0x5C4F, 0x6CD9, 0x3D63, 0x0DF5, + 0x20C8, 0x105E, 0x41E4, 0x7172, 0xE4D1, 0xD447, 0x85FD, 0xB56B, + 0xA8FA, 0x986C, 0xC9D6, 0xF940, 0x6CE3, 0x5C75, 0x0DCF, 0x3D59, + 0x30AC, 0x003A, 0x5180, 0x6116, 0xF4B5, 0xC423, 0x9599, 0xA50F, + 0xB89E, 0x8808, 0xD9B2, 0xE924, 0x7C87, 0x4C11, 0x1DAB, 0x2D3D, + 0x4190, 0x7106, 0x20BC, 0x102A, 0x8589, 0xB51F, 0xE4A5, 0xD433, + 0xC9A2, 0xF934, 0xA88E, 0x9818, 0x0DBB, 0x3D2D, 0x6C97, 0x5C01, + 0x51F4, 0x6162, 0x30D8, 0x004E, 0x95ED, 0xA57B, 0xF4C1, 0xC457, + 0xD9C6, 0xE950, 0xB8EA, 0x887C, 0x1DDF, 0x2D49, 0x7CF3, 0x4C65, + 0x6158, 0x51CE, 0x0074, 0x30E2, 0xA541, 0x95D7, 0xC46D, 0xF4FB, + 0xE96A, 0xD9FC, 0x8846, 0xB8D0, 0x2D73, 0x1DE5, 0x4C5F, 0x7CC9, + 0x713C, 0x41AA, 0x1010, 0x2086, 0xB525, 0x85B3, 0xD409, 0xE49F, + 0xF90E, 0xC998, 0x9822, 0xA8B4, 0x3D17, 0x0D81, 0x5C3B, 0x6CAD, + 0x8320, 0xB3B6, 0xE20C, 0xD29A, 0x4739, 0x77AF, 0x2615, 0x1683, + 0x0B12, 0x3B84, 0x6A3E, 0x5AA8, 0xCF0B, 0xFF9D, 0xAE27, 0x9EB1, + 0x9344, 0xA3D2, 0xF268, 0xC2FE, 0x575D, 0x67CB, 0x3671, 0x06E7, + 0x1B76, 0x2BE0, 0x7A5A, 0x4ACC, 0xDF6F, 0xEFF9, 0xBE43, 0x8ED5, + 0xA3E8, 0x937E, 0xC2C4, 0xF252, 0x67F1, 0x5767, 0x06DD, 0x364B, + 0x2BDA, 0x1B4C, 0x4AF6, 0x7A60, 0xEFC3, 0xDF55, 0x8EEF, 0xBE79, + 0xB38C, 0x831A, 0xD2A0, 0xE236, 0x7795, 0x4703, 0x16B9, 0x262F, + 0x3BBE, 0x0B28, 0x5A92, 0x6A04, 0xFFA7, 0xCF31, 0x9E8B, 0xAE1D, + 0xC2B0, 0xF226, 0xA39C, 0x930A, 0x06A9, 0x363F, 0x6785, 0x5713, + 0x4A82, 0x7A14, 0x2BAE, 0x1B38, 0x8E9B, 0xBE0D, 0xEFB7, 0xDF21, + 0xD2D4, 0xE242, 0xB3F8, 0x836E, 0x16CD, 0x265B, 0x77E1, 0x4777, + 0x5AE6, 0x6A70, 0x3BCA, 0x0B5C, 0x9EFF, 0xAE69, 0xFFD3, 0xCF45, + 0xE278, 0xD2EE, 0x8354, 0xB3C2, 0x2661, 0x16F7, 0x474D, 0x77DB, + 0x6A4A, 0x5ADC, 0x0B66, 0x3BF0, 0xAE53, 0x9EC5, 0xCF7F, 0xFFE9, + 0xF21C, 0xC28A, 0x9330, 0xA3A6, 0x3605, 0x0693, 0x5729, 0x67BF, + 0x7A2E, 0x4AB8, 0x1B02, 0x2B94, 0xBE37, 0x8EA1, 0xDF1B, 0xEF8D +}; + +#else + +#ifdef SHIFT_RIGHT // 如果是右移 + +#define CRC_GEN 0xa001 // 使用多项式 0xa001 + +#else // 如果是左移 + +#define CRC_GEN 0x8005 // 使用多项式 0x8005 + +#endif // #ifdef SHIFT_RIGHT + +#endif + +//------------------------------------------------------------------------------- + +u16 addCrc16(u16 crcword, u8 dat) +{ +#ifdef USE_CRC_TABLE // 查表法crc + crcword = (crcword >> 8) ^ CRC16_LIST[(crcword ^ dat) & 0xFF]; +#else + u8 i; + crcword ^= dat; + for (i = 0; i < 8; i++) + { +#ifdef SHIFT_RIGHT // 右移计算crc + if ((LOBYTE(crcword) & 0x01) != 0) + { + crcword >>= 1; + crcword ^= CRC_GEN; + } + else + { + crcword >>= 1; + } +#else // 左移计算crc + if ((HIBYTE(crcword) & 0x80) != 0) + { + crcword <<= 1; + crcword ^= CRC_GEN; + } + else + { + crcword <<= 1; + } +#endif + } + +#endif + return crcword; +} + +//------------------------------------------------------------------------------- + +u16 calcCrc16(u8 * pBuf, int lenBuf) +{ + int i; + u16 crcword = CRC_INIT; + + for (i = 0; i < lenBuf; i++) + { + crcword = addCrc16(crcword, pBuf[i]); + } + + return crcword; +} + +//------------------------------------------------------------------------------- + +u8 calcCheckSum8(u8 * pBuf, int lenBuf) +{ + int i; + u8 checksum = 0; + + for (i = 0; i < lenBuf; i++) + { + checksum += pBuf[i]; + } + + return checksum; + +} + +//------------------------------------------------------------------------------- + +u32 calcCheckSum32(u8 * pBuf, int lenBuf) +{ + int i; + u32 checksum = 0; + + for (i = 0; i < lenBuf; i++) + { + checksum += pBuf[i]; + } + + return checksum; + +} + + diff --git a/machine/comm/crc16.h b/machine/comm/crc16.h new file mode 100644 index 0000000..25dc808 --- /dev/null +++ b/machine/comm/crc16.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------- +// File Name: crc16.h +// Brief: +// Version: 1.0.0 +// Create Date: 2017/05/08 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2017, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2017/05/08 +//------------------------------------------------------------------------------- + + +#ifndef __CRC16_H__ +#define __CRC16_H__ + +/* + + CRC16 算法模块 + + 提供查表法和移位法两种 CRC16 算法 + +*/ + +#include "typedef.h" + +#define USE_CRC_TABLE // 用查表法crc, 否则, 用移位法计算 +#define SHIFT_RIGHT // 右移位 + +#ifdef USE_CRC_TABLE + +#define CRC_INIT 0x0000 // 并且crc初值为0 + +#else + +#ifdef SHIFT_RIGHT // 如果是右移 + +#define CRC_INIT 0xFFFF // crc初值为0xFFFF + +#else // 如果是左移 + +#define CRC_INIT 0x0000 // 并且crc初值为0 + +#endif // #ifdef SHIFT_RIGHT + +#endif + + +u16 calcCrc16(u8 * pBuf, int lenBuf); + + +u8 calcCheckSum8(u8 * pBuf, int lenBuf); + +u32 calcCheckSum32(u8 * pBuf, int lenBuf); + + +#endif + diff --git a/machine/comm/crc32.cpp b/machine/comm/crc32.cpp new file mode 100644 index 0000000..bb93930 --- /dev/null +++ b/machine/comm/crc32.cpp @@ -0,0 +1,74 @@ + +//------------------------------------------------------------------------------- +// File Name: crc32.c +// Brief: +// Version: 1.0.0 +// Create Date: 2018/08/13 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2019, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2018/08/13 +//------------------------------------------------------------------------------- + + +#include "crc32.h" + +//------------------------------------------------------------------------------- + +static const u32 CRC32_LIST[256] = +{ + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL, +}; + + +u32 addCrc32(u32 crcword, u8 dat) +{ + return (crcword >> 8) ^ CRC32_LIST[((crcword ^ dat) & 0xFF)]; +} + +u32 calcCrc32(u8 * pBuf, int lenBuf) +{ + int i; + u32 crcword = CRC32_INIT; + + for (i = 0; i < lenBuf; i++) + { + crcword = addCrc32(crcword, pBuf[i]); + } + + return crcword; +} diff --git a/machine/comm/crc32.h b/machine/comm/crc32.h new file mode 100644 index 0000000..c89f3d8 --- /dev/null +++ b/machine/comm/crc32.h @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------- +// File Name: crc32.h +// Brief: +// Version: 1.0.0 +// Create Date: 2018/08/13 +// Create by: Marshal Lee +// Copyright: +// Copyright (c) 2019, Richpeace Co., LTD. +// All rights reserved. +// +// Modify by: Marshal Lee +// Modify Date: 2018/08/13 +//------------------------------------------------------------------------------- + + +#ifndef __CRC32_H__ +#define __CRC32_H__ + +/* + CRC32 算法模块 +*/ + +#include "typedef.h" + +#define CRC32_INIT 0xffffffff // crc初值 + + +u32 addCrc32(u32 crcword, u8 dat); +u32 calcCrc32(u8 * pBuf, int lenBuf); + + + +#endif diff --git a/machine/comm/protocol.h b/machine/comm/protocol.h new file mode 100644 index 0000000..bf4e492 --- /dev/null +++ b/machine/comm/protocol.h @@ -0,0 +1,466 @@ +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include "comm.h" + +// 文件传输控制结构 +#define LEN_RSV_BMP MAX_EXDP_LEN // 位图大小 +#define MAX_FILE_SIZE (LEN_RSV_BMP*MAX_EXDP_LEN*8) // 最大文件字节数 按位图大小设定 + +#define PARA_NUM 256 + +// 传输文件类型 +#define FILE_TYPE_DAT 0x00 // 数据文件 +#define FILE_TYPE_PGM 0x02 // 升级文件 +#define FILE_TYPE_PLOT 0x06 // 喷墨数据 + +#define MCPARA_MACH 0 // 机器参数 +#define MCPARA_WORK 1 // 工作参数 + +// 传输有效标志定义 +#define TRANS_NONE 0x00 // 无效 +#define TRANS_ACTIVE 0x5A // 有效 + +// 传输结果代码定义 +#define TRANS_NOT_BEG 0x00 // 没有收到启动命令 +#define TRANS_READY 0x01 // 准备好接收 +#define TRANS_DOING 0x02 // 正在接收 +#define TRANS_DONE 0x03 // 接收完成 +#define TRANS_REQUEST 0x04 // 请求传输模式 + +// 上位机发送命令 +#define UCMD_GET_MC_INFO 0x0001 // 读取机器信息 +#define UCMD_GET_MC_STATUS 0x0002 // 读取机器状态 +#define UCMD_GET_MC_PARAS 0x0003 // 读取机器参数 +#define UCMD_GET_TRANS_RESULT 0x0007 // 读取传输结果 +#define UCMD_SET_MC_STATUS 0x0102 // 设置机器状态 +#define UCMD_SET_MC_PARAS 0x0103 // 设置机器参数 +#define UCMD_SET_MEM_DATA 0x0104 // 设置内存数据 +#define UCMD_SET_FILE_PARAS 0x0105 // 设置文件参数 +#define UCMD_SET_EXEC_PROGRESS 0x0106 // 设置执行进度 +#define UCMD_SET_INSTALLMENT 0x0107 // 设置分期密码 +#define UCMD_SET_ELAPSED_TIME 0x0108 // 设置经过的时间 +#define UCMD_SET_DEF_PARA 0x0109 // 设置默认参数 +#define UCMD_SET_FILE_EXDATA 0x010F // 设置文件扩展数据 +#define UCMD_ACT_BYHAND 0x0201 // 手动控制命令 +#define UCMD_MC_WORK 0x0202 // 机器工作命令 +#define UCMD_MOVE_TO 0x0203 // 移动XY到坐标 +#define UCMD_MOVE_OFST 0x0205 // XY移动偏移量 +#define UCMD_START_TRANS 0x0301 // 启动文件传输 +#define UCMD_TRANS_FILE_DATA 0x0302 // 文件传输命令 +#define UCMD_SET_FILE_LIST 0x0304 // 设置文件列表 +#define UCMD_MC_UPDATE 0x0401 // 下位机升级 + +// 下位机发送命令 +#define DCMD_REQUEST_DAT 0x8000 // 请求文件数据 +#define DCMD_SEND_MC_INFO 0x8001 // 发送机器信息 +#define DCMD_SEND_MC_STATUS 0x8002 // 发送机器状态 +#define DCMD_SEND_MC_PARAS 0x8003 // 发送机器参数 +#define DCMD_SEND_FILE_INFO 0x8006 // 发送文件信息 +#define DCMD_SEND_TRANS_RESULT 0x8007 // 发送传输结果 +#define DCMD_SEND_DEBUG_INFO 0x8010 // 调试信息发送 + +// 状态码定义如下-设置 +#define MC_STA_CLENA_ERR 0x0000 // 清除错误 +#define MC_STA_EN_WORK 0x0001 // 允许工作(状态) +#define MC_STA_DIS_WORK 0x0002 // 禁止工作(状态) +#define MC_STA_EN_TIME 0x0003 // 允许工作(时间) +#define MC_STA_DIS_TIME 0x0004 // 禁止工作(时间) +#define MC_CLEAN_COUNT 0x0005 // 产量计数清零 +#define MC_STA_MANUAL 0x0006 // 手动工作状态 +#define MC_STA_AUTO 0x0007 // 自动工作状态 +#define MC_FILE_SWITCH 0x0008 // 文件切换 +#define MC_INVALID_FILE 0x0009 // 文件失效命令 + +// 工作控制功能 +#define WORK_START 0x0001 // 启动工作 +#define WORK_PAUSE 0x0002 // 暂停工作 + + +// 喷墨图像按照黑白位图的格式存储 + +// 将整个喷墨图像位图分割为 (墨盒数量*300) 个像素宽度的块 +// 每个块按照一个文件传输 + +// 数据列表, 描述整个位图 +typedef struct +{ + // 0 + u32 fileId; // 文件标识 + + // 1 + u32 totalWidth; // 位图宽度,以像素为单位 + u32 totalHeight; // 位图高度,以像素为单位 + + // 3 + u32 blkNums; // 分块个数 + u32 blkWidth; // 分块位图宽度,以像素为单位 + + // 5 + u32 rev[16-5]; +}__attribute__ ((packed)) PlotFileList; + +// 自定义压缩位图文件头 +typedef struct +{ + // 0 + u32 fileId; // 整个位图文件标识 + u32 blkIdx; // 当前位图块号(位图分块后的编号) + u32 datSize; // 本块位图数据区的大小(字节数) + u32 biWidth; // 本块位图有效宽度,以像素为单位 + u32 biHeight; // 本块位图有效高度,以像素为单位 + u32 dataChecksum; // 本块位图数据累加校验和 + u32 begPosY; // 本块起始位置(像素单位) + u32 endPosY; // 本块结束位置(像素单位) + + // 32 + u8 compType; // 本块位图压缩类型, =0, 不压缩; =1, 按字节压缩; + u8 compDir; // 本块位图压缩方向, =0, 从上到下; =1, 从下到上;(喷墨方向) + + // 34 + u8 rev[64-2-34]; // 保留 + + // 62 + u16 checkCrc; // 前面字段的CRC校验 + +}__attribute__ ((packed)) CompBmpHead; + +// 机器信息结构定义 +typedef struct +{ + // 0 + char softwareVerStr[32]; // 软件版本 + + // 32 + char rev[1024-32]; + +} __attribute__ ((packed)) MCInfo; + +typedef struct +{ + u32 buf[PARA_NUM]; +} __attribute__ ((packed)) ParaStruct; + +// 升级文件头 +typedef struct +{ + // 0x00 + char fileName[32]; // 文件名称 + // 0x20 + u32 dataSize; // 数据字节数 + u32 dataChecksum; // 数据累加校验和 + + // 0x28 + u8 reserved1[0x30-0x28]; // 保留区1 + // 0x30 + u8 reserved2[0x64-0x30]; // 保留区1 + + // 0x64 + u8 reserved3[0x80-0x64]; // 保留区2 + + // 0x80 + u8 reserved4[0x100-0x80]; +}__attribute__ ((packed)) AppFileHead; + +typedef struct +{ + int transphase; + int filetransing; + int waitcount; + + u8 transActive; // 传输结构有效 + u8 transflag; // 接收进度标志 = 0, 接收未开始; = 1, 正在接收; = 2,接收完成。 + u8 fileType; // 文件类型 + u8 fileIdx; // 为文件编号,最多支持16个文件 + u16 fileId; // 文件ID + u16 packetSize; // 包的大小 + u32 packetNum; // 包的个数 + + AppFileHead * pAppHead; + CompBmpHead * pBmpHead; + u8 * pDatBuff; + + u16 lenBmp; // 位图有效长度 + u8 rsvBitmap[LEN_RSV_BMP]; // 文件接收进度标志位图 + +}FileTransCtrl; + +// 机器状态数据结构定义 +typedef struct +{ + // 0 + u32 workStatus; // 工作状态位图 + // .0 允许时限。=0,使用时限已到,不允许下位机工作;=1,允许下位机工作; + // .1 允许状态。=0,界面钳制,不允许下位机工作;=1,允许下位机工作; + // .2 机器状态。=0,手动工作状态; =1,自动工作状态 + // .3 钥匙状态。=0,关闭状态; =1,打开状态 + // .4 文件接收标志。= 0,初始状态。= 1,收到了文件 + // .5 参数接收标志。= 0,初始状态。= 1,收到了参数 + // .6 正在忙标志。= 0,空闲(可以接收文件和参数)。= 1,工作中(不会接收文件和参数) + // .7 上料状态。=0,手动上料状态; =1,自动上料状态 + // .8 参数更新标志。 =1,下位机更新了参数 + // .9 模拟工作标志。=1, 处于模拟工作状态 + // .10 允许扫描条码状态。=1, 允许 + // .11 允许拍照状态。=1, 允许 + // .12 正在工作标志 + // .13 传感信号扫描中标志 + // .14 相机校准模式中标志 + // .15 + // .16 + // .17 + // .18 + // .19 取模板框状态 + // .20 放模板框状态 + // .21 匹绣, 0:退出匹绣,主轴归零 1:进入匹绣,扎针,允许移框 + // .22 断线检测, 0:退出断线检测状态, 1:进入断线检测状态 + + // 1 + u32 errorCode; // 错误代码 + u32 fileIdx; // 文件序号 + u32 dataIdx; // 数据索引 + u32 runSpeed; // 运动速度 主轴转速 + u32 runAction; // 执行动作代码 * + u32 runSteps; // 当前执行步骤 * + u32 outCounter; // 产量计数 +} __attribute__ ((packed)) MCStatus; + + +//OperPacket +typedef union +{ + DataPacket packet; + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 toggle; + u8 rev[6]; + u16 crc; + } __attribute__ ((packed)) getMcInfo; // 读取机器信息 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 paraType; + u16 paraId; + u8 rev[4]; + u16 crc; + } __attribute__ ((packed)) getMcParas; // UCMD_GET_MC_PARAS 读取机器参数 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u8 fileType; + u8 fileIdx; + u8 rev[6]; + u16 crc; + } __attribute__ ((packed)) getFileInfo; // UCMD_GET_FILE_INFO 读取文件信息 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 fileId; + u8 rev[6]; + u16 crc; + } __attribute__ ((packed)) getTransResult; // UCMD_GET_TRANS_RESULT 读取传输结果 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 upObj; + u16 upFileID; + u32 checksum; + u16 crc; + } __attribute__ ((packed)) mcUpdate; // UCMD_MC_UPDATE 系统升级 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 staCode; + u16 para; + u8 rev[4]; + u16 crc; + } __attribute__ ((packed)) setMcStatus; // UCMD_SET_MC_STATUS 设置机器状态 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 paraType; + u16 paraId; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) setParas; // UCMD_SET_MC_PARAS 设置下位机参数 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u8 fileType; + u8 fileIdx; + u16 fileId; + + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) startTrans; // UCMD_START_TRANS 启动文件传输 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 pktIdx; + u16 fileId; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) transFileData; // UCMD_TRANS_FILE_DATA 文件数据传输 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + u32 fileIdxMap; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + + } __attribute__ ((packed)) setFilesList; // 设置文件列表 UCMD_SET_FILE_LIST + + //---------------------------------- + // 下位机发送命令 + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u8 fileType; + u8 fileIdx; + u16 fileId; + u32 datBlockIdx; // 数据包索引(每个包1024字节) + + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dRequestDatBlock; // DCMD_REQUEST_DAT 请求文件数据 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 toggle; + u8 rev[2]; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dSendMcInfo; // DCMD_SEND_MC_INFO 发送机器信息 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 toggle; + u8 rev[2]; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dSendMcStatus; // DCMD_SEND_MC_STATUS 发送机器状态 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 paraType; + u16 paraId; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dSendMcParas; // DCMD_SEND_MC_PARAS 发送机器参数 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u8 fileType; + u8 fileIdx; + u8 rev[2]; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dSendFileInfo; // DCMD_SEND_FILE_INFO 发送文件信息 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 exLen; + u16 exCrc; + + u16 fileId; + u8 active; + u8 result; + u16 crc; + + u8 exData[MAX_EXDP_LEN]; + } __attribute__ ((packed)) dSendTransResult; // DCMD_SEND_TRANS_RESULT 发送传输结果 + + struct + { + u8 sync[DP_SYNC_LEN]; + u16 cmdCode; + + u16 workCode; + u32 para1; + u16 para2; + u16 crc; + } __attribute__ ((packed)) mcWork; // UCMD_MC_WORK 机器工作命令 + +}OperPacket; + + +#endif // PROTOCOL_H diff --git a/machine/comm/typedef.h b/machine/comm/typedef.h new file mode 100644 index 0000000..e66849e --- /dev/null +++ b/machine/comm/typedef.h @@ -0,0 +1,16 @@ +#ifndef TYPEDEF_H +#define TYPEDEF_H + +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef unsigned long int DWORD; + +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned int u32; +typedef char s8; +typedef short int s16; +typedef int s32; + +#endif // TYPEDEF_H diff --git a/machine/machine.cpp b/machine/machine.cpp new file mode 100644 index 0000000..2742b2f --- /dev/null +++ b/machine/machine.cpp @@ -0,0 +1,1061 @@ +#include "machine.h" + +QByteArray g_receiveBuff; +DataExFuns g_exfuns = {NULL,NULL,NULL,NULL,NULL}; + +// 发送数据 +int operatorSendData(u8 * pDatBuf, int len) +{ + if (pDatBuf != NULL && len != 0) + { + // 不准备通过该函数发送数据 + } + return 0; +} + +// 得到发送缓冲区空闲长度 +int operatorGetSdFreeLen(void) +{ + return 0; // 认没有空间 +} + +// 接收数据 +int operatorGetData(u8 * pDat, int expectLen) +{ + int len = g_receiveBuff.size(); + if (len > expectLen) + { + len = expectLen; + } + + //if (len != 0 && pDat != NULL) + if (len == expectLen && pDat != NULL) //使len等于expectLen(串口下接收数据暴露的问题) + { + memcpy(pDat, g_receiveBuff.data(), len); + g_receiveBuff.remove(0, len); + } + else + { + len = 0; + } + + return len; +} + +// 已接收数据长度 +int operatorGetRsLen(void) +{ + return g_receiveBuff.size(); +} + +void delayMs(u32 ms) +{ + QDateTime oldTime, curTime; + oldTime = QDateTime::currentDateTime(); + while(1) + { + curTime = QDateTime::currentDateTime(); + if(oldTime.msecsTo(curTime) > ms) + { + break; + } + } +} + +void initDataExFuns(void) +{ + g_exfuns.sendCommData = operatorSendData; + g_exfuns.getCommData = operatorGetData; + g_exfuns.getRsvLen = operatorGetRsLen; + g_exfuns.getTrsFreeLen = operatorGetSdFreeLen; + + g_exfuns.delay = delayMs; +} + +Machine::Machine(QObject *parent) : QObject(parent) +{ + m_connected = 0; + m_mcParaEn = 0; + m_wkParaEn = 0; + m_transBreak = 0; + + m_pTcpClient = new TcpClient(); + m_pTcpBmpThread = new QThread(); + m_pCreatPrintDat = new CreatPrintBmp(); + m_mcPrintInfo.clear(); + + memset(&m_transCtrl, 0, sizeof(FileTransCtrl)); // 文件传输信息 + m_transCtrl.pAppHead = new AppFileHead; + m_transCtrl.pBmpHead = new CompBmpHead; + m_transCtrl.pDatBuff = new u8[MAX_FILE_SIZE]; + + m_pPlotFileList = new PlotFileList(); + memset(m_pPlotFileList,0,sizeof(PlotFileList)); + + m_pCompBmpHead = new CompBmpHead(); + memset(m_pCompBmpHead,0,sizeof(CompBmpHead)); + + m_pSendTimer = new QTimer(this); + m_pSendTimer->setInterval(100); // 设置定时间隔100毫秒 + connect(m_pSendTimer, SIGNAL(timeout()), this, SLOT(onSendTimer())); + initDataExFuns(); + + qRegisterMetaType("BmpDatInfo");//对自定义类型注册 +} + +Machine::~Machine() +{ + if(m_pTcpBmpThread != NULL) + { + m_pTcpBmpThread->quit(); + m_pTcpBmpThread->wait(); + delete m_pTcpBmpThread; + } + + if(m_pSendTimer != NULL) + { + m_pSendTimer->stop(); + delete m_pSendTimer; + m_pSendTimer = NULL; + } + + if (m_transCtrl.pAppHead != NULL) + { + delete []m_transCtrl.pAppHead; + m_transCtrl.pAppHead = NULL; + } + + if (m_transCtrl.pBmpHead != NULL) + { + delete []m_transCtrl.pBmpHead; + m_transCtrl.pBmpHead = NULL; + } + + if (m_transCtrl.pDatBuff != NULL) + { + delete []m_transCtrl.pDatBuff; + m_transCtrl.pDatBuff = NULL; + } +} + +void Machine::startFileTrans(FileTransCtrl &transCtrl) +{ + int rslt; + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.startTrans.cmdCode = UCMD_START_TRANS; + sendPacket.startTrans.fileType = transCtrl.fileType; + sendPacket.startTrans.fileIdx = transCtrl.fileIdx; + sendPacket.startTrans.fileId = transCtrl.fileId; + + if(transCtrl.fileType == FILE_TYPE_PLOT) + { + rslt = packetAVLDP(&sendPacket.packet, (u8*)transCtrl.pBmpHead, sizeof(CompBmpHead)); + } + + if (rslt == 0) + { + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET+sizeof(CompBmpHead)); + emit(siSendData(dat)); + } +} + +void Machine::startFileDyTrans(FileTransCtrl &transCtrl) +{ + int rslt = -1; + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.startTrans.cmdCode = UCMD_START_TRANS; + sendPacket.startTrans.fileType = transCtrl.fileType; + sendPacket.startTrans.fileIdx = transCtrl.fileIdx; + sendPacket.startTrans.fileId = transCtrl.fileId; + + if( transCtrl.fileType == FILE_TYPE_DAT) + { + //rslt = packetAVLDP(&sendPacket.packet, (u8*)transCtrl.pFileHead, sizeof(DataDs16FileHead)); + } + else + { + return ; + } + + if (rslt == 0) + { + if( transCtrl.fileType == FILE_TYPE_DAT) + { + + } + } +} + +// 文件数据传输 +void Machine::transFileData(FileTransCtrl &transCtrl, int pktidx) +{ + int rslt; + int actsize; + u8 buff[MAX_EXDP_LEN]; + + if (pktidx < 0 || transCtrl.pDatBuff == NULL) + { + return; + } + + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.transFileData.cmdCode = UCMD_TRANS_FILE_DATA; + sendPacket.transFileData.fileId = transCtrl.fileId; + sendPacket.transFileData.pktIdx = pktidx; + + if (pktidx < (int)transCtrl.packetNum) + { + if(transCtrl.fileType == FILE_TYPE_PLOT) + { + actsize = transCtrl.pBmpHead->datSize - pktidx*transCtrl.packetSize; + + if (actsize >= transCtrl.packetSize) + { + actsize = transCtrl.packetSize; + } + else + { + memset(buff, 0, MAX_EXDP_LEN); + } + } + else + { + actsize = 0; + } + + memcpy(buff, &(transCtrl.pDatBuff[pktidx*transCtrl.packetSize]), actsize); + qDebug("TransFileData pktidx=%d", pktidx); + + rslt = packetAVLDP(&sendPacket.packet, buff, MAX_EXDP_LEN); + if (rslt == 0) + { + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET+MAX_EXDP_LEN); + emit(siSendData(dat)); + } + } +} + +void Machine::setAParasToMachine(int type, int idx, u32 value) +{ + int rslt; + OperPacket sendPacket; + int size = sizeof(value); + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.setParas.cmdCode = UCMD_SET_MC_PARAS; + sendPacket.setParas.paraType = (u16)type; + sendPacket.setParas.paraId = idx; + + rslt = packetAVLDP(&sendPacket.packet, (u8*)&value, size); + + if (rslt == 0) + { + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET + size); + emit(siSendData(dat)); + } +} + +void Machine::setMcStatusAsMc(u8 *buff, u16 len, int toggle) +{ + memcpy(&m_mcStatus, buff, len); + emit(siStatusChange(toggle)); +} + +void Machine::updateFirmware() +{ + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.mcUpdate.cmdCode = UCMD_MC_UPDATE; + sendPacket.mcUpdate.upObj = 0; + sendPacket.mcUpdate.upFileID = 0; + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +int Machine::dySendFileProc(int type, int idx, int id, u8 *pDatBuff) +{ + if (pDatBuff == NULL) + { + return -1; + } + + int datSize = sizeof(pDatBuff); + if (datSize <= 0 || datSize > MAX_FILE_SIZE) + { + qDebug("datSize <= 0 || datSize > MAX_FILE_SIZE, not support"); + return -2; + } + + QTime delayTime; + int counter = 0; + delayTime.start(); + + if (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + return -3; + } + + while (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + if (delayTime.elapsed() > 1000) + { + counter++; + qDebug("%d. wait old file trans over", counter); + delayTime.restart(); + } + + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } + + m_transBreak = 0; + + m_transCtrl.fileType = (u8)type; + m_transCtrl.fileIdx = (u8)idx; + m_transCtrl.fileId = (u16)id; + memcpy(m_transCtrl.pDatBuff, pDatBuff, datSize); + m_transCtrl.packetSize = MAX_EXDP_LEN; + m_transCtrl.packetNum = (datSize + MAX_EXDP_LEN - 1) / MAX_EXDP_LEN; + + qDebug("StartFileTrans, fileType=%d, fileIdx=%d, fileId=%d, packetNum=%d, ", + m_transCtrl.fileType, m_transCtrl.fileIdx, m_transCtrl.fileId, m_transCtrl.packetNum); + + m_transCtrl.filetransing = 1; + m_transCtrl.transflag = TRANS_REQUEST; + m_transCtrl.transActive = TRANS_ACTIVE; + startFileDyTrans(m_transCtrl); + m_transCtrl.filetransing = 0; + + return 0; +} + +// 发送文件过程 +int Machine::sendAPPFileProc(int type, int idx, int id, AppFileHead & fileHead, u8 * pDatBuff) +{ + if (pDatBuff == NULL || fileHead.dataSize <= 0) + { + return -1; + } + + if (fileHead.dataSize > MAX_FILE_SIZE) + { + qDebug("fileHead.dataSize > MAX_FILE_SIZE, not support"); + return -2; + } + + QTime delayTime; + int counter = 0; + delayTime.start(); + + while (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + if (delayTime.elapsed() > 1000) + { + counter++; + qDebug("%d. wait old file trans over", counter); + delayTime.restart(); + } + + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } + + m_transBreak = 0; + + // 拷贝数据到传输控制结构 + m_transCtrl.fileType = (u8)type; + m_transCtrl.fileIdx = (u8)idx; + m_transCtrl.fileId = (u16)id; + memcpy(m_transCtrl.pAppHead, &fileHead, sizeof(AppFileHead)); + memcpy(m_transCtrl.pDatBuff, pDatBuff, fileHead.dataSize); + m_transCtrl.packetSize = MAX_EXDP_LEN; + m_transCtrl.packetNum = (fileHead.dataSize + MAX_EXDP_LEN - 1 ) / MAX_EXDP_LEN; + + qDebug("StartFileTrans, fileType=%d, fileIdx=%d, fileId=%d, packetNum=%d, ", + m_transCtrl.fileType, m_transCtrl.fileIdx, m_transCtrl.fileId, m_transCtrl.packetNum); + + m_transCtrl.transphase = SEND_STEP1; + m_transCtrl.filetransing = 1; + + // 启动定时器 + m_pSendTimer->start(); + return 0; +} + +void Machine::mcWorkCmd(int workcode, int para1, int para2) +{ + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.mcWork.cmdCode = UCMD_MC_WORK; + sendPacket.mcWork.workCode = (u16)workcode; + sendPacket.mcWork.para1 = (u32)para1; + sendPacket.mcWork.para2 = (u16)(para2); + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +void Machine::deleteFilePrintDat(int fileIdx) +{ + m_pCreatPrintDat->setDeleteFile(fileIdx); +} + +void Machine::moveFilePrintDat(int fileIdx,int dir) +{ + m_pCreatPrintDat->setMoveFile(fileIdx,dir); +} + +void Machine::invalidateWorkFile(int idx) +{ + setMcStatus(MC_INVALID_FILE, idx); +} + +void Machine::creatPrintDat(int fileIdx) +{ + m_pCreatPrintDat->setMcPrintInfo(fileIdx,&m_mcPrintInfo); + emit siCreatData(); +} + +void Machine::setIpAndPort(QString mcName, QString serverIp, quint16 serverPort, QString localIp, quint16 localPort) +{ + m_mcName = mcName; + m_mcIp = serverIp; + m_pTcpClient->setIpAndPort(serverIp,serverPort,localIp,localPort); +} + +void Machine::startCommunication() +{ + //TCP通讯 + m_pTcpClient->moveToThread(m_pTcpBmpThread); // 移动对象到线程中 + connect(m_pTcpBmpThread, SIGNAL(started()), m_pTcpClient, SLOT(connectToServer()) ); + connect(m_pTcpBmpThread, SIGNAL(finished()), m_pTcpClient, SLOT(deleteLater()) ); // 退出删除对象 + connect(m_pTcpClient, SIGNAL(siConnectSta(int)), + this, SLOT(slotConnectSta(int)), Qt::AutoConnection); // 连接状态改变 + connect(m_pTcpClient, SIGNAL(siConnectErr(QString)), + this, SLOT(slotConnectErr(QString)), Qt::AutoConnection); // 接收到通讯错误 + connect(m_pTcpClient, SIGNAL(siReceiveData(QByteArray)), + this, SLOT(slotReceiveData(QByteArray)), Qt::AutoConnection); // 接收到数据 + connect(this, SIGNAL(siSendData(QByteArray)), + m_pTcpClient, SLOT(slotSendData(QByteArray)), Qt::AutoConnection); // 发送数据的槽 + + //生成打印数据 + m_pCreatPrintDat->moveToThread(m_pTcpBmpThread); + connect(m_pTcpBmpThread, SIGNAL(finished()), m_pCreatPrintDat, SLOT(deleteLater()) ); // 退出删除对象 + connect(this, SIGNAL(siCreatData()), + m_pCreatPrintDat, SLOT(slotCreatBmp()), Qt::QueuedConnection); // 发送数据的槽 + connect(this, SIGNAL(siSendDataDone()), + m_pCreatPrintDat, SLOT(slotCreatNextBmpBlockDat()), Qt::QueuedConnection); // 发送数据的槽 + connect(this, SIGNAL(siCreatBmpBlockDatAndSend()), + m_pCreatPrintDat, SLOT(slotCreatNextBmpBlockDat()), Qt::QueuedConnection); // 发送数据的槽 + + connect(m_pCreatPrintDat, SIGNAL(siSendFileListDatToMc(int)), + this, SLOT(slotSendPlotFileListToMc(int)), Qt::QueuedConnection); // 发送数据的槽 + connect(m_pCreatPrintDat, SIGNAL(siSendDatToMc(QByteArray,BmpDatInfo)), + this, SLOT(slotSendDatToMc(QByteArray,BmpDatInfo)), Qt::QueuedConnection); // 发送数据的槽 + connect(m_pCreatPrintDat, SIGNAL(siDeleteFileFinish()), + this, SIGNAL(siDeleteFileFinish())); // 删除文件 + + m_pTcpBmpThread->start(); // 启动线程 +} + +void Machine::getInfoFromMachine() +{ + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.getMcInfo.cmdCode = UCMD_GET_MC_INFO; + + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +void Machine::getParasFromMachine(int type, int id) +{ + int mctype = -1; + int wktype = -1; + + if (type == -1) + { + mctype = MCPARA_MACH; + wktype = MCPARA_WORK; + m_mcParaEn = 0; + m_wkParaEn = 0; + } + else + { + if(type == MCPARA_MACH) + { + mctype = MCPARA_MACH; + m_mcParaEn = 0; + } + if(type == MCPARA_WORK) + { + wktype = MCPARA_WORK; + m_wkParaEn = 0; + } + } + + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.getMcParas.cmdCode = UCMD_GET_MC_PARAS; + + if (mctype == MCPARA_MACH) + { + sendPacket.getMcParas.paraType = (u16)mctype; + } + + if (wktype == MCPARA_WORK) + { + sendPacket.getMcParas.paraType = (u16)wktype; + } + + sendPacket.getMcParas.paraId = id; + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +// 读取传输结果 +void Machine::getTransResultFromMachine(int fileid) +{ + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.getTransResult.cmdCode = UCMD_GET_TRANS_RESULT; + sendPacket.getTransResult.fileId = (u16)fileid; + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +void Machine::sleep(int sec) +{ + QTime dieTime = QTime::currentTime().addSecs(sec);//延时sec秒 + //QTime dieTime = QTime::currentTime().addMSecs(msec);//延时msec毫秒 + while( QTime::currentTime() < dieTime ) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); +} + +void Machine::setMcStatus(int stacode, int para) +{ + OperPacket sendPacket; + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.setMcStatus.cmdCode = UCMD_SET_MC_STATUS; + sendPacket.setMcStatus.staCode = (u16)stacode; + sendPacket.setMcStatus.para = (u16)para; + packetAFLDP(&sendPacket.packet); + + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET); + emit(siSendData(dat)); +} + +void Machine::setParasToMachine(ParaStruct ¶) +{ + int rslt; + OperPacket sendPacket; + int size = sizeof(ParaStruct); + memset(&sendPacket, 0, sizeof(OperPacket)); + //sendPacket.setParas.cmdCode = UCMD_SET_MC_PARAS; + + rslt = packetAVLDP(&sendPacket.packet, (u8*)¶, size); + + if (rslt == 0) + { + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET + size); + emit(siSendData(dat)); + } +} + +void Machine::setAMcPara(int id, u32 value) +{ + setAParasToMachine(MCPARA_MACH, id, value); +} + +void Machine::setAWkPara(int id, u32 value) +{ + setAParasToMachine(MCPARA_WORK, id, value); +} + +// 启动工作 +void Machine::startWork() +{ + mcWorkCmd(WORK_START); +} + +// 暂停工作 +void Machine::pauseWork() +{ + mcWorkCmd(WORK_PAUSE); +} + +int Machine::sendFileProc( int idx, u8 *dat, int datSize) +{ + if(dat == NULL) + { + return -1; + } + + if (datSize <= 0 || datSize > MAX_FILE_SIZE) + { + return -2; + } + + QTime delayTime; + int counter = 0; + delayTime.start(); + + if (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + return -3; + } + + while (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + if (delayTime.elapsed() > 1000) + { + counter++; + qDebug("%d. wait old file trans over", counter); + delayTime.restart(); + } + + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + } + + m_transBreak = 0; + + m_transCtrl.fileIdx = (u8)idx; + memcpy(m_transCtrl.pDatBuff, dat, datSize); + m_transCtrl.packetSize = MAX_EXDP_LEN; + m_transCtrl.packetNum = (datSize + MAX_EXDP_LEN - 1) / MAX_EXDP_LEN; + + qDebug("StartFileTrans, fileType=%d, fileIdx=%d, packetNum=%d, ", + m_transCtrl.fileType, m_transCtrl.fileIdx, m_transCtrl.packetNum); + + m_transCtrl.transphase = SEND_STEP1; + m_transCtrl.filetransing = 1; + m_pSendTimer->start(); + return 0; +} + +void Machine::slotConnectSta(int sta) +{ + m_connected = sta; +} + +void Machine::slotConnectErr(QString errinfo) +{ + if(errinfo.length() <= 0){} +} + +// 接收到数据的槽函数 +void Machine::slotReceiveData(QByteArray dat) +{ + int rslt; + DataPacket packet; + OperPacket * operpkt = (OperPacket *)(&packet); + + //qDebug() << "SlotReceiveData size=" << dat.size(); + g_receiveBuff.append(dat); + //qDebug()<<"append dat size"< 0) // 收到数据包 + { + //qDebug()<<"getANormalPacket rslt="<packet.fldp.cmd; + switch(operpkt->packet.fldp.cmd) // 先按固定长度解析 + { + case DCMD_REQUEST_DAT: // 请求文件数据 + { + if (m_transCtrl.transActive == TRANS_ACTIVE) + { + if (1 && + m_transCtrl.transflag == TRANS_REQUEST && // 请求传输数据模式 + m_transCtrl.fileType == operpkt->dRequestDatBlock.fileType && + m_transCtrl.fileIdx == operpkt->dRequestDatBlock.fileIdx && + m_transCtrl.fileId == operpkt->dRequestDatBlock.fileId && + 1 ) + { + qDebug("in request mode, send block idx=%d", operpkt->dRequestDatBlock.datBlockIdx); + transFileData(m_transCtrl, operpkt->dRequestDatBlock.datBlockIdx); + } + } + break; + } + case DCMD_SEND_MC_INFO: // 发送机器信息 + { + memcpy(&m_mcInfo, operpkt->dSendMcInfo.exData, sizeof(MCInfo)); + emit(siMcInfoChange( )); + break; + } + + case DCMD_SEND_MC_STATUS: // 发送机器状态 + { + setMcStatusAsMc(operpkt->dSendMcStatus.exData, operpkt->dSendMcStatus.exLen, operpkt->dSendMcStatus.toggle); + break; + } + + case DCMD_SEND_MC_PARAS: // 发送机器参数 + { + int type; + + type = operpkt->dSendMcParas.paraType; + if (operpkt->dSendMcParas.exLen == sizeof(ParaStruct)) + { + if (type == MCPARA_MACH) + { + memcpy(&m_mcPara, operpkt->dSendMcParas.exData, sizeof(ParaStruct)); + m_mcParaEn = 1; + } + else if (type == MCPARA_WORK) + { + memcpy(&m_wkPara, operpkt->dSendMcParas.exData, sizeof(ParaStruct)); + m_wkParaEn = 1; + } + else + { + break; + } + + //因为之前请求了机器参数和工作参数,所以当两个参数都返回时,再触发信号和槽 + // if( m_mcParaEn==1 && m_wkParaEn==1) + { + printf("emit SiParaChange\r\n"); + emit(siParaChange(type, 0)); + } + } + else if (operpkt->dSendMcParas.exLen == sizeof(u32)) + { + int id, idx; + id = operpkt->dSendMcParas.paraId; + idx = id - 1; + if (idx > 0 && idx < PARA_NUM) + { + idx *= sizeof(u32); + if (type == MCPARA_MACH) + { + memcpy((u8*)(&m_mcPara)+idx, operpkt->dSendMcParas.exData, sizeof(u32)); + m_mcParaEn = 1; + } + else if (type == MCPARA_WORK) + { + memcpy((u8*)(&m_wkPara)+idx, operpkt->dSendMcParas.exData, sizeof(u32)); + m_wkParaEn = 1; + } + else + { + break; + } + emit(siParaChange(type, id)); + } + } + + break; + } + + case DCMD_SEND_TRANS_RESULT: // 发送传输结果 + { + printf("get DCMD_SEND_TRANS_RESULT\r\n"); + m_transCtrl.lenBmp = operpkt->dSendTransResult.exLen; + m_transCtrl.transActive = operpkt->dSendTransResult.active; + m_transCtrl.transflag = operpkt->dSendTransResult.result; + if (m_transCtrl.lenBmp != 0) + { + memcpy(m_transCtrl.rsvBitmap, operpkt->dSendTransResult.exData, m_transCtrl.lenBmp); + } + m_fileTransEn = 1; + + emit (siTransResultChange()); + + break; + } + + default: + break; + } + } + else + { + break; + } + }while(1); +} + +void Machine::onSendTimer() +{ + int rslt; + rslt = 0; + + //qDebug("file trans timer"); + + if (m_transBreak != 0) // 中断传输 + { + //qDebug("break file trans"); + m_transCtrl.transphase = SEND_STEP5; + } + + if (m_transCtrl.transphase == SEND_STEP0) // 文件失效 + { + m_fileTransEn = 0; + qDebug("SEND_STEP1 InvalidateWorkFile"); + invalidateWorkFile(m_transCtrl.fileIdx); // 文件失效 + m_transCtrl.transphase = SEND_STEP1; + rslt = 1; + } + else if (m_transCtrl.transphase == SEND_STEP1) // 启动文件传输 + { + m_fileTransEn = 0; + startFileTrans(m_transCtrl); + + qDebug("trans progress %d/%d", 0, m_transCtrl.packetNum); + m_totalSendNum = 0; + m_totalPacketNum = m_transCtrl.packetNum; + emit(siTransProgress(m_transCtrl.fileType, m_totalSendNum, m_totalPacketNum)); // 发送进度信号 + m_transCtrl.transphase = SEND_STEP2; + rslt = 1; + } + else if (m_transCtrl.transphase == SEND_STEP2) // 读取传输结果 + { + qDebug("SEND_STEP2 send GetTransResult cmd"); + + m_fileTransEn = 0; + getTransResultFromMachine(m_transCtrl.fileId); + m_transCtrl.transphase = SEND_STEP3; + rslt = 1; + } + else if (m_transCtrl.transphase == SEND_STEP3) // 根据传输结果传输文件数据 + { + if (m_fileTransEn == 1) + { + qDebug("GetTransResult from machine"); + + if (m_transCtrl.transActive == TRANS_ACTIVE) + { + if (m_transCtrl.transflag == TRANS_READY || // 准备好接收 + m_transCtrl.transflag == TRANS_DOING || // 正在接收 + 0) + { + //qDebug("trans sta = TRANS_READY or TRANS_DOING flag=%d", m_transCtrl.transflag); + + int thissendnum = 0; + int totalsendnum = 0; + int send_count = 400; + + if ( m_transCtrl.fileType == FILE_TYPE_PGM) //升级等文件(小文件) + { + send_count = 25; + } + + u8 mod, temp; + for (int i = 0; i < m_transCtrl.lenBmp; i++) + { + temp = m_transCtrl.rsvBitmap[i]; + mod = 0x01; + for (int j = 0; j < 8; j++) + { + if ((temp & mod) == 0) + { + if (thissendnum < send_count) // 每发送send_count个包,查询一次结果 + { + thissendnum++; + + transFileData(m_transCtrl, i*8+j); + } + } + else + { + totalsendnum++; + } + mod <<= 1; + } + } + m_totalSendNum = totalsendnum; + m_totalPacketNum = m_transCtrl.packetNum; + emit(siTransProgress(m_transCtrl.fileType, m_totalSendNum, m_totalPacketNum)); // 发送进度信号 + m_transCtrl.transphase = SEND_STEP2; // 重新发送查询命令 + } + else if (m_transCtrl.transflag == TRANS_DONE) // 接收完成 + { + //qDebug("trans sta = TRANS_DONE"); + + emit siSendDataDone(); + + m_totalSendNum = m_transCtrl.packetNum; + m_totalPacketNum = m_transCtrl.packetNum; + emit(siTransProgress(m_transCtrl.fileType, m_totalSendNum, m_totalPacketNum)); // 发送进度信号 + m_transCtrl.transphase = SEND_STEP4; + + if( m_transCtrl.fileType == FILE_TYPE_PGM ) + { + updateFirmware(); + } + } + else if (m_transCtrl.transflag == TRANS_REQUEST) // 请求传输数据模式 + { + //qDebug("trans sta = TRANS_REQUEST, sta=%d", m_transCtrl.transflag); + m_transCtrl.transphase = SEND_ANSWER; + } + else // if (m_transCtrl.transflag == TRANS_NOT_BEG) // 没有收到启动命令 + { + //qDebug("trans sta = TRANS_NOT_BEG, sta=%d, back to SEND_STEP1", m_transCtrl.transflag); + m_transCtrl.transphase = SEND_STEP1; // 重新发送启动文件传输 + } + } + else + { + //qDebug("transActive != TRANS_ACTIVE, back to SEND_STEP1"); + m_transCtrl.transphase = SEND_STEP1; // 重新发送启动文件传输 + } + rslt = 1; + } + else + { + if (m_transCtrl.waitcount > SEND_STEP_MAX) // 1秒没有回复 + { + //qDebug("waitcount > SEND_STEP_MAX, back to SEND_STEP2"); + m_transCtrl.transphase = SEND_STEP2; // 重新发送查询命令 + rslt = 1; + } + } + } + + if (rslt == 0) + { + m_transCtrl.waitcount++; + } + else + { + m_transCtrl.waitcount = 0; + } + + if ( m_transCtrl.transphase != SEND_STEP1 && + m_transCtrl.transphase != SEND_STEP2 && + m_transCtrl.transphase != SEND_STEP3 ) // 结束 + { + //qDebug("trans file over, step=%d", m_transCtrl.transphase); + if (m_transCtrl.transphase == SEND_STEP4) + { + m_totalSendNum = 0; + m_totalPacketNum = 0; + emit(siTransProgress(m_transCtrl.fileType, m_totalSendNum, m_totalPacketNum)); // 发送结束信号(成功) + } + else + { + m_totalSendNum = -1; + m_totalPacketNum = -1; + emit(siTransProgress(m_transCtrl.fileType, m_totalSendNum, m_totalPacketNum)); // 发送结束信号(失败) + } + m_pSendTimer->stop(); // 停止定时器 + m_transCtrl.filetransing = 0; + } +} + +void Machine::slotSendDatToMc(QByteArray dat, BmpDatInfo bmpInfo) +{ + if(m_connected == Connected) + { + if (dat.size() <= 0 || m_pCompBmpHead == NULL) + { + return; + } + + QTime delayTime; + int counter = 0; + delayTime.start(); + + while (m_transCtrl.filetransing != 0) // 已经有文件在传输 + { + if (delayTime.elapsed() > 1000) + { + counter++; + qDebug("%d. wait old file trans over", counter); + delayTime.restart(); + } + + QCoreApplication::processEvents(QEventLoop::AllEvents, 100);//进度条 + } + + qDebug()<<"dat.size()"<fileId = m_pPlotFileList->fileId; + m_pCompBmpHead->blkIdx = bmpInfo.blkIdx; + m_pCompBmpHead->datSize = dat.size(); + m_pCompBmpHead->biWidth = bmpInfo.biWidth; + m_pCompBmpHead->biHeight = bmpInfo.biHeight; + m_pCompBmpHead->begPosY = bmpInfo.begPosY; + m_pCompBmpHead->endPosY = bmpInfo.endPosY; + m_pCompBmpHead->compType = bmpInfo.compType; + m_pCompBmpHead->compDir = bmpInfo.compDir; + m_pCompBmpHead->dataChecksum = calcCheckSum32((u8*)dat.data() , dat.size()); // 数据累加校验和 + int len = sizeof(m_pCompBmpHead)-sizeof(m_pCompBmpHead->checkCrc); + m_pCompBmpHead->checkCrc = calcCrc16((u8*)m_pCompBmpHead, len); // 前面字段的CRC校验 + + if (m_pCompBmpHead->datSize <= 0 || m_pCompBmpHead->datSize > MAX_FILE_SIZE) + { + qDebug("m_pCompBmpHead->datSize <= 0 || m_pCompBmpHead->datSize > MAX_FILE_SIZE, not support"); + return; + } + + m_transBreak = 0; + + m_transCtrl.fileType = (u8)FILE_TYPE_PLOT; + m_transCtrl.fileId = m_pCompBmpHead->fileId; + memcpy(m_transCtrl.pBmpHead, m_pCompBmpHead, sizeof(CompBmpHead)); + memcpy(m_transCtrl.pDatBuff, dat, m_pCompBmpHead->datSize); + m_transCtrl.packetSize = MAX_EXDP_LEN; + m_transCtrl.packetNum = (m_pCompBmpHead->datSize + MAX_EXDP_LEN - 1) / MAX_EXDP_LEN; + + qDebug("StartFileTrans, fileType=%d, fileIdx=%d, fileId=%d, packetNum=%d, ", + m_transCtrl.fileType, m_transCtrl.fileIdx, m_transCtrl.fileId, m_transCtrl.packetNum); + + m_transCtrl.transphase = SEND_STEP1; + m_transCtrl.filetransing = 1; + + m_pSendTimer->start(); + qDebug()<<"slotSendDatToMc"; + return; + } +} + +void Machine::slotSendPlotFileListToMc(int idx) +{ + if(m_connected == Connected) + { + int oft = (int)(m_mcPrintInfo.m_filesList[idx].m_startPoint*MMPIXELY); + qDebug()<<"slotSendPlotFileListToMc"; + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + u32 id =qrand() % (UINT16_MAX);//产生0到UINT16_MAX的随机数 + m_pPlotFileList->fileId = id; + m_pPlotFileList->totalWidth = (m_mcPrintInfo.m_filesList[idx].m_pic.width() - oft) * m_mcPrintInfo.m_filesList[idx].m_printNum; + m_pPlotFileList->totalHeight = m_mcPrintInfo.m_filesList[idx].m_pic.height() * m_mcPrintInfo.m_filesList[idx].m_printNum; + m_pPlotFileList->blkNums = m_mcPrintInfo.m_filesList[idx].m_totalBlocks * m_mcPrintInfo.m_filesList[idx].m_printNum; + m_pPlotFileList->blkWidth = PIXMAPWIDTH; + + int rslt; + OperPacket sendPacket; + int size = sizeof(PlotFileList); + memset(&sendPacket, 0, sizeof(OperPacket)); + sendPacket.setParas.cmdCode = UCMD_SET_FILE_LIST; + + rslt = packetAVLDP(&sendPacket.packet, (u8*)m_pPlotFileList, size); + + if (rslt == 0) + { + QByteArray dat((char*)(&sendPacket.packet), LEN_NORMAL_PACKET + size); + emit(siSendData(dat)); + emit siCreatBmpBlockDatAndSend(); + } + } +} + +void Machine::breakFileTrans() +{ + m_transBreak = 1; +} diff --git a/machine/machine.h b/machine/machine.h new file mode 100644 index 0000000..e46aeb2 --- /dev/null +++ b/machine/machine.h @@ -0,0 +1,140 @@ +#ifndef MACHINE_H +#define MACHINE_H + +#include "tcp/tcpclient.h" +#include "bmp/creatprintbmp.h" +#include "printinfo/mcfiles.h" +#include "machine/comm/crc16.h" + +#define SEND_STEP0 0 +#define SEND_STEP1 1 +#define SEND_STEP2 2 +#define SEND_STEP3 3 +#define SEND_STEP4 4 +#define SEND_STEP5 5 + +#define SEND_STEP_MAX 10 +#define SEND_ANSWER 100 + +class Machine : public QObject +{ + Q_OBJECT +public: + explicit Machine(QObject *parent = NULL); + virtual ~Machine(); + +protected: + QString m_mcName; + QString m_mcIp; + +private: + // 通讯线程和网络连接 + TcpClient * m_pTcpClient; + QThread * m_pTcpBmpThread; + + //生成打印数据 + CreatPrintBmp * m_pCreatPrintDat; + + MCInfo m_mcInfo; // 机器信息 + ParaStruct m_mcPara; // 机器参数信息 配置信息 + ParaStruct m_wkPara; // 工作参数信息 + int m_totalSendNum;//传输文件时总共发送的包数 + int m_totalPacketNum;//传输文件时总的包数 + + QTimer *m_pSendTimer; + FileTransCtrl m_transCtrl; + int m_fileTransEn; + int m_transBreak; + + PlotFileList *m_pPlotFileList;//文件数据列表 + CompBmpHead *m_pCompBmpHead;//压缩位图文件头 + +private: + int m_connected; // 机器连接状态. 0, 未连接; 1, 连接中; 2, + MCStatus m_mcStatus; // 机器状态 + int m_mcParaEn; + int m_wkParaEn; + +public: + McPrintInfo m_mcPrintInfo;//机器打印信息(包括机器的连接状态和工作状态) + +private: + void startFileTrans(FileTransCtrl & transCtrl); + void startFileDyTrans(FileTransCtrl & transCtrl);//开始动态传输文件 + void transFileData(FileTransCtrl & transCtrl, int pktidx); + void setAParasToMachine(int type, int idx, u32 value); + void setMcStatusAsMc(u8 * buff, u16 len, int toggle); + void updateFirmware(); // 下位机升级 + + // 连接 +public: + inline int isConnected() const { return m_connected; } + +public: + void setIpAndPort(QString mcName, QString serverIp, quint16 serverPort, QString localIp, quint16 localPort); + void startCommunication(); + + //机器信息 + inline const MCInfo &getMcInfo() { return m_mcInfo; } + inline int getTotalSendNum() { return m_totalSendNum; } + inline int getTotalPacketNum() { return m_totalPacketNum; } + inline const MCStatus & getMcStatus() {return m_mcStatus; } + inline const ParaStruct & getMcPara() {/*m_mcParaEn = 0; */ return m_mcPara; } + inline const ParaStruct & getWkPara() {/*m_wkParaEn = 0; */ return m_wkPara; } + + void getInfoFromMachine(); + void getParasFromMachine(int type, int id); // 读取机器参数 + void getTransResultFromMachine(int fileid); + void sleep(int sec); + +public: + void setMcStatus(int stacode, int para = 0); // 设置机器状态 + // 设置机器参数 + void setParasToMachine(ParaStruct & para); + void setAMcPara(int id, u32 value); + void setAWkPara(int id, u32 value); + + void startWork(); // 启动工作 + void pauseWork(); // 暂停工作 + // 文件传输命令 + int sendFileProc(int idx, u8 *dat, int datSize); + int dySendFileProc(int type, int idx, int id, u8 * pDatBuff); //动态传输文件 + int sendAPPFileProc(int type, int idx, int id, AppFileHead &fileHead, u8 *pDatBuff); //发送升级文件 + + // 机器工作命令 + void mcWorkCmd(int workcode, int para1 = 0 , int para2 = 0); + + void creatPrintDat(int fileIdx); //生成打印数据 + void deleteFilePrintDat(int fileIdx);//删除文件打印数据 + void moveFilePrintDat(int fileIdx,int dir = -1);//移动(上下移)文件打印数据 + + void invalidateWorkFile(int idx = 0); // 文件失效 + +signals: + // 发送数据到机器的信号 + void siSendData(QByteArray dat); + void siSendDataDone(); + void siStatusChange(int); // 状态改变信号 + + void siMcInfoChange(); // 机器信息改变信号 + void siParaChange(int type, int id); // 参数更新信号 + void siTransResultChange(); // 文件传输结果信号 + void siTransProgress(u8 fileType, int send, int total); // 文件传输结果信号 + void siCreatData(); //生成要发送的数据 + void siCreatBmpBlockDatAndSend();//生成位图数据块数据并发送 + void siDeleteFileFinish(); + void siMoveFileFinish(); + +private slots: + void slotConnectSta(int sta); // 连接状态改变的槽函数 + void slotConnectErr(QString errinfo); // 接收到通讯错误槽函数 + void slotReceiveData(QByteArray dat); // 接收到数据的槽函数 + void onSendTimer(void); + void slotSendDatToMc(QByteArray dat, BmpDatInfo bmpInfo);//发送打印数据 + void slotSendPlotFileListToMc(int idx);//发送设置文件列表 + +public slots: + void breakFileTrans(); // 打断文件传输 +}; + +#endif // MACHINE_H diff --git a/machine/printinfo/mcfiles.h b/machine/printinfo/mcfiles.h new file mode 100644 index 0000000..e3f6792 --- /dev/null +++ b/machine/printinfo/mcfiles.h @@ -0,0 +1,232 @@ +#ifndef MCFILES_H +#define MCFILES_H + +#include +#include +#include +#include "machine/comm/protocol.h" +#include "datafile/hpgl/marker.h" + +//连接状态 +enum ConnectState +{ + InitConnect = 0,//初始值 + NoConnect = 1, //未连接 + Connectting = 2, //连接中 + Connected = 3 //已连接 +}; + +//工作状态 +enum WorkState +{ + NotBusy = 0,//空闲中 + Busying = 1 //工作中 +}; + +class McFilesInfo +{ +public: + s16 m_creatDataFlag;//是否已经生成数据的标志 + s16 m_creatBmpFlag;//是否已经生成bmp的标志 + QString m_fileName;//文件名称 + QString m_filePath;//文件路径 + s16 m_fileType;//文件类型 + QRect m_fileRect;//图形被包络的矩形区域 + s16 m_printNum;//打印份数 + s16 m_startPoint;//打印起始点 + QString m_printState;//打印状态 + QPicture m_pic;//文件-图片 + QBitmap m_pixmap;//图片-图片 + s16 m_totalBlocks;//总块数 + s16 m_curPrintBlock;//当前打印块数 + s16 m_printedBlockNum;//已打印块数 + s16 m_leaveBlockNum;//剩余打印块数 + s16 m_selectBlockNum;//当前选择块数 + Marker m_marker;//数据 + + void clear() + { + QPicture pic; + + m_creatDataFlag = -1; + m_creatBmpFlag = -1;//是否已经生成bmp的标志 + m_fileName.clear();//文件名称 + m_filePath.clear();//文件路径 + m_fileType = 0;//文件类型 + m_printNum = 0;//打印份数 + m_startPoint = 0;//打印起始点 + m_printState.clear();//打印状态 + m_pic = pic; + m_pixmap.clear(); + m_totalBlocks = 0;//总块数 + m_curPrintBlock = 0;//当前打印块数 + m_printedBlockNum = 0;//已打印块数 + m_leaveBlockNum = 0;//剩余打印块数 + m_selectBlockNum = 0;//当前选择块数 + m_marker.Initialize(); + } + + McFilesInfo() + { + m_creatDataFlag = -1; + m_creatBmpFlag = -1;//是否已经生成bmp的标志 + m_fileName.clear();//文件名称 + m_filePath.clear();//文件路径 + m_fileType = 0;//文件类型 + m_printNum = 0;//打印份数 + m_startPoint = 0;//打印起始点 + m_printState.clear();//打印状态 + m_totalBlocks = 0;//总块数 + m_curPrintBlock = 0;//当前打印块数 + m_printedBlockNum = 0;//已打印块数 + m_leaveBlockNum = 0;//剩余打印块数 + m_selectBlockNum = 0;//当前选择块数 + m_marker.Initialize(); + } + McFilesInfo(const McFilesInfo &item) + { + m_creatDataFlag = item.m_creatDataFlag;//是否已经生成数据的标志 + m_creatBmpFlag = item.m_creatBmpFlag;//是否已经生成bmp的标志 + m_fileName = item.m_fileName;//文件名称 + m_filePath = item.m_filePath;//文件路径 + m_fileType = item.m_fileType;//文件类型 + m_fileRect = item.m_fileRect;//图形被包络的矩形区域 + m_printNum = item.m_printNum;//打印份数 + m_startPoint = item.m_startPoint;//打印起始点 + m_printState = item.m_printState;//打印状态 + m_pic = item.m_pic; + m_pixmap = item.m_pixmap; + m_totalBlocks = item.m_totalBlocks;//总块数 + m_curPrintBlock = item.m_curPrintBlock;//当前打印块数 + m_printedBlockNum = item.m_printedBlockNum;//已打印块数 + m_leaveBlockNum = item.m_leaveBlockNum;//剩余打印块数 + m_selectBlockNum = item.m_selectBlockNum;//当前选择块数 + m_marker = item.m_marker; + } + ~McFilesInfo() {} + McFilesInfo & operator=(const McFilesInfo &item) + { + m_creatDataFlag = item.m_creatDataFlag;//是否已经生成数据的标志 + m_creatBmpFlag = item.m_creatBmpFlag;//是否已经生成bmp的标志 + m_fileName = item.m_fileName;//文件名称 + m_filePath = item.m_filePath;//文件路径 + m_fileType = item.m_fileType;//文件类型 + m_fileRect = item.m_fileRect;//图形被包络的矩形区域 + m_printNum = item.m_printNum;//打印份数 + m_startPoint = item.m_startPoint;//打印起始点 + m_printState = item.m_printState;//打印状态 + m_pic = item.m_pic; + m_pixmap = item.m_pixmap; + m_totalBlocks = item.m_totalBlocks;//总块数 + m_curPrintBlock = item.m_curPrintBlock;//当前打印块数 + m_printedBlockNum = item.m_printedBlockNum;//已打印块数 + m_leaveBlockNum = item.m_leaveBlockNum;//剩余打印块数 + m_selectBlockNum = item.m_selectBlockNum;//当前选择块数 + m_marker = item.m_marker; + return *this; + } +}; +Q_DECLARE_METATYPE(McFilesInfo) + +class McPrintInfo +{ +public: + s16 m_mcNum;//机器号 + s16 m_loadFileFinishFlag;//自动加载文件完成标志(包括自动绘图目录和上次未打印完的) + QString m_mcName;//机器名称 + int m_mcConnState;//机器连接状态 + int m_mcWorkState;//机器工作状态 + int m_mcSendProgress;//机器文件发送进度 + int m_totalNums;//要发送的总块数 + int m_sendedlNums;//已发送的总块数 + QString m_ip;//机器ip + s16 m_port;//机器端口 + s16 m_fileNums;//文件数量 + s16 m_curCreatPrintDatFileIdx;//当前正在生成打印数据的文件索引 + long long m_fileTotalLength;//文件总长度 + QList m_filesList;//图片列表 + + void clear() + { + m_mcNum = 0; + m_loadFileFinishFlag = -1; + m_mcName.clear(); + m_mcConnState = InitConnect; + m_mcWorkState = NotBusy; + m_mcSendProgress = 0; + m_totalNums = 0; + m_sendedlNums = 0; + m_ip.clear(); + m_port = 0; + m_fileNums = 0; + m_fileTotalLength = 0; + m_curCreatPrintDatFileIdx = -1; + for(int i = 0; i < m_filesList.size(); i++) + { + m_filesList[i].clear(); + } + m_filesList.clear(); + } + + McPrintInfo() + { + m_mcNum = 0; + m_loadFileFinishFlag = -1; + m_mcName.clear(); + m_mcConnState = InitConnect; + m_mcWorkState = NotBusy; + m_mcSendProgress = 0; + m_mcSendProgress = 0; + m_totalNums = 0; + m_sendedlNums = 0; + m_ip.clear(); + m_port = 0; + m_fileNums = 0; + m_fileTotalLength = 0; + m_curCreatPrintDatFileIdx = -1; + m_filesList.clear(); + } + + McPrintInfo(const McPrintInfo &item) + { + m_mcNum = item.m_mcNum; + m_loadFileFinishFlag = item.m_loadFileFinishFlag; + m_mcName = item.m_mcName; + m_mcConnState = item.m_mcConnState; + m_mcWorkState = item.m_mcWorkState; + m_mcSendProgress = item.m_mcSendProgress; + m_totalNums = item.m_totalNums; + m_sendedlNums = item.m_sendedlNums; + m_ip = item.m_ip; + m_port = item.m_port; + m_fileNums = item.m_fileNums; + m_fileTotalLength = item.m_fileTotalLength; + m_curCreatPrintDatFileIdx = -1; + m_filesList = item.m_filesList; + } + + ~McPrintInfo() {} + + McPrintInfo & operator=(const McPrintInfo &item) + { + m_mcNum = item.m_mcNum; + m_loadFileFinishFlag = item.m_loadFileFinishFlag; + m_mcName = item.m_mcName; + m_mcConnState = item.m_mcConnState; + m_mcWorkState = item.m_mcWorkState; + m_mcSendProgress = item.m_mcSendProgress; + m_totalNums = item.m_totalNums; + m_sendedlNums = item.m_sendedlNums; + m_ip = item.m_ip; + m_port = item.m_port; + m_fileNums = item.m_fileNums; + m_fileTotalLength = item.m_fileTotalLength; + m_curCreatPrintDatFileIdx = -1; + m_filesList = item.m_filesList; + return *this; + } +}; + +Q_DECLARE_METATYPE(McPrintInfo) + +#endif // MCFILES_H diff --git a/machine/tcp/qbindtcpsocket.cpp b/machine/tcp/qbindtcpsocket.cpp new file mode 100644 index 0000000..740c43f --- /dev/null +++ b/machine/tcp/qbindtcpsocket.cpp @@ -0,0 +1,186 @@ +#include "qbindtcpsocket.h" + +#include + +QBindTcpSocket::QBindTcpSocket(QObject *parent): + QTcpSocket(parent) +{ + +} + +QBindTcpSocket::~QBindTcpSocket() +{ + +} + +int QBindTcpSocket::bindAddrAndPort(QString localAddr, quint16 localPort) +{ + QString str = localAddr; + QHostAddress addr(str); + setLocalAddress(addr); + setLocalPort(localPort); + return 0; +} + +//------------------------------- +TcpConnectDetect::TcpConnectDetect(QObject *parent) : + QObject(parent), + m_pDetectSocket(NULL), + m_localip(DEF_LOCAL_IP), + m_localport(DEF_LOCAL_PORT), + m_serverip(DEF_SERVER_IP), + m_serverport(DEF_SERVER_PORT) +{ +} + +TcpConnectDetect::~TcpConnectDetect() +{ + if (m_pDetectSocket == NULL) + { + m_pDetectSocket->disconnectFromHost(); + m_pDetectSocket->waitForDisconnected(); + m_pDetectSocket->close(); + delete m_pDetectSocket; + } +} + +void TcpConnectDetect::detectStart() +{ + qDebug("TcpConnectDetect start"); + if (m_pDetectSocket == NULL) + { + m_pDetectSocket = new QBindTcpSocket; + } +} + +int TcpConnectDetect::connectDetect() +{ + int connectsta = 0; + int rslt; + + // qDebug() << "TcpConnectDetect " << QThread::currentThread(); + + if (m_pDetectSocket == NULL) + { + return 0; + } + if (m_localip.isEmpty() == false) + { + m_pDetectSocket->bindAddrAndPort(m_localip, m_localport); + } + m_pDetectSocket->abort(); + m_pDetectSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); + m_pDetectSocket->connectToHost(m_serverip, m_serverport); + + do + { + rslt = m_pDetectSocket->waitForConnected(4000); // 等待连接 + + qDebug("bind Detect connect rslt=%d", rslt); + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport; + + switch(m_pDetectSocket->state()) + { + case QAbstractSocket::ConnectedState: + { + // 如果连接上,说明 m_pClientSocket 连接已经无效, 需要断开重新连接 + // 先断开测试连接 + m_pDetectSocket->disconnectFromHost(); + m_pDetectSocket->waitForDisconnected(); + connectsta = 1; + // 发送断开主连接的信号 + qDebug() << "detect is Connected, disconnect all"; + + break; + } + case QAbstractSocket::UnconnectedState: + { + // qDebug() << "detect is Unconnected err=" << m_pDetectSocket->error() << ", info:" << m_pDetectSocket->errorString(); + + switch (m_pDetectSocket->error()) + { + case QAbstractSocket::SocketTimeoutError: // 连接超时,说明已经断开 + case QAbstractSocket::NetworkError: // 网络错误, 主机不可连接, 可能已经断开 + { + qDebug() << "detect is timout, disconnect all"; + connectsta = 1; + // 发送断开主连接的信号 + break; + } + case QAbstractSocket::ConnectionRefusedError: // 拒绝连接, 说明连接还在 + { + connectsta = 2; + // qDebug() << "Connection Refused, old connect is alive"; + break; + } + /* + case QAbstractSocket::RemoteHostClosedError: + case QAbstractSocket::HostNotFoundError: + case QAbstractSocket::SocketAccessError: + case QAbstractSocket::SocketResourceError: + case QAbstractSocket::SocketTimeoutError: + case QAbstractSocket::DatagramTooLargeError: + case QAbstractSocket::AddressInUseError: + case QAbstractSocket::SocketAddressNotAvailableError: + case QAbstractSocket::UnsupportedSocketOperationError: + case QAbstractSocket::UnfinishedSocketOperationError: + case QAbstractSocket::ProxyAuthenticationRequiredError: + case QAbstractSocket::SslHandshakeFailedError: + case QAbstractSocket::ProxyConnectionRefusedError: + case QAbstractSocket::ProxyConnectionClosedError: + case QAbstractSocket::ProxyConnectionTimeoutError: + case QAbstractSocket::ProxyNotFoundError: + case QAbstractSocket::ProxyProtocolError: + case QAbstractSocket::UnknownSocketError: + */ + default: + { + // 继续检测 + connectsta = 2; + qDebug() << " retry"; + break; + } + } // 错误处理结束 + } + case QAbstractSocket::ConnectingState: + { + // qDebug() << "detect is Connecting"; + // qDebug() << "localip=" << m_localip << "localport=" << m_localport; + // 继续等待 + break; + } + case QAbstractSocket::HostLookupState: + case QAbstractSocket::BoundState: + case QAbstractSocket::ListeningState: + case QAbstractSocket::ClosingState: + default: + { + // 继续等待 + qDebug("detect sta is %d\r\n", m_pDetectSocket->state()); + break; + } + } + + if (connectsta != 0) + { + break; + } + + }while(1); + + + m_pDetectSocket->close(); + + // 发送本次测试连接的状态信号 + emit(siConnectSta(connectsta)); + return connectsta; +} + +void TcpConnectDetect::setIpAndPort(QString localip, quint16 localport, QString serverip, quint16 serverport) +{ + m_localip = localip; + m_localport = localport; + m_serverip = serverip; + m_serverport = serverport; +} diff --git a/machine/tcp/qbindtcpsocket.h b/machine/tcp/qbindtcpsocket.h new file mode 100644 index 0000000..b433b66 --- /dev/null +++ b/machine/tcp/qbindtcpsocket.h @@ -0,0 +1,53 @@ +#ifndef QBINDTCPSOCKET_H +#define QBINDTCPSOCKET_H + +#define DEF_SERVER_IP "192.168.16.253" +#define DEF_SERVER_PORT 5000 +#define DEF_LOCAL_IP "" +#define DEF_LOCAL_PORT 5001 + + +#include + +class QBindTcpSocket : public QTcpSocket +{ + +public: + QBindTcpSocket(QObject *parent = 0); + virtual ~QBindTcpSocket(); + +public: + int bindAddrAndPort(QString localAddr, quint16 localPort); +}; + +#if(1) +class TcpConnectDetect : public QObject +{ + Q_OBJECT +public: + explicit TcpConnectDetect(QObject *parent = NULL); + virtual ~TcpConnectDetect(); + +signals: + void siConnectSta(int sta); // 网络连接信号 +public: + +public slots: + void detectStart(); + int connectDetect(); + +private: + QBindTcpSocket * m_pDetectSocket; + +public: + void setIpAndPort(QString localip, quint16 localport, QString serverip, quint16 serverport); + +private: + QString m_localip; + quint16 m_localport; + QString m_serverip; + quint16 m_serverport; +}; +#endif + +#endif // QBINDTCPSOCKET_H diff --git a/machine/tcp/tcpclient.cpp b/machine/tcp/tcpclient.cpp new file mode 100644 index 0000000..b85ea6f --- /dev/null +++ b/machine/tcp/tcpclient.cpp @@ -0,0 +1,460 @@ +#include "tcpclient.h" + +#include +#include +#include + +TcpClient::TcpClient(QObject *parent) : + QObject(parent), + m_pClientSocket(NULL), + m_pConnectCheckTimer(NULL), + m_connected(0), + m_pConnectDetect(NULL), + m_detect(0), + m_localip(DEF_LOCAL_IP), + m_localport(DEF_LOCAL_PORT), + m_serverip(DEF_SERVER_IP), + m_serverport(DEF_SERVER_PORT) +{ + m_pClientSocket = new QBindTcpSocket(this); + m_pClientSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + connect(m_pClientSocket, SIGNAL(readyRead()), this, SLOT(receiveServerData())); + connect(m_pClientSocket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(displaySocketError(QAbstractSocket::SocketError))); + // connect(m_pClientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(netStateChanged(QAbstractSocket::SocketState))); + + m_pConnectCheckTimer = new QTimer(this); + connect(m_pConnectCheckTimer, SIGNAL(timeout()), this, SLOT(connectCheck())); +} + +TcpClient::~TcpClient() +{ + if(m_pClientSocket !=NULL) + { + m_pClientSocket->disconnectFromHost(); + m_pClientSocket->waitForDisconnected(); + m_pClientSocket->close(); + delete m_pClientSocket; + m_pClientSocket = NULL; + } + + if(m_pConnectCheckTimer != NULL) + { + m_pConnectCheckTimer->stop(); + delete m_pConnectCheckTimer; + m_pConnectCheckTimer = NULL; + } +} + +void TcpClient::setIpAndPort(QString serverIp, quint16 serverPort, QString localIp, quint16 localPort) +{ + m_serverip = serverIp; + m_serverport = serverPort; + m_localip = localIp; + m_localport = localPort; +} + +void TcpClient::connectToServer() +{ + if (m_pClientSocket == NULL) + { + qDebug() << "m_pClientSocket not alloc"; + return; + } + + if (m_connected == 0) + { + if (m_pConnectDetect == NULL) + { + m_pConnectDetect = new TcpConnectDetect; + } + qDebug() << "ConnectToServer"; + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport; + + m_pConnectDetect->setIpAndPort(m_localip, m_localport, m_serverip, m_serverport); + + connect(this, SIGNAL(siDetectHost()), m_pConnectDetect, SLOT(connectDetect()), Qt::QueuedConnection); + connect(m_pConnectDetect, SIGNAL(siConnectSta(int)), this, SLOT(detectStatus(int)), Qt::QueuedConnection); + + m_pConnectCheckTimer->start(1000); + m_connected = 1; + m_detect = 1; + } +} + +void TcpClient::disConnectFromServer() +{ + if (m_connected != 0) + { + m_pConnectCheckTimer->stop(); + + if (m_pClientSocket != NULL) + { + m_pClientSocket->disconnectFromHost(); + m_pClientSocket->waitForDisconnected(); + m_pClientSocket->close(); + } + + m_connected = 0; + m_detect = 0; + } +} + +// 发送数据的槽 +void TcpClient::slotSendData(QByteArray dat) +{ + if (m_pClientSocket != NULL) + { + m_pClientSocket->write(dat); + } +} + +// 自动检测连接 +void TcpClient::connectCheck() +{ + if (m_pClientSocket == NULL) + { + qDebug() << "Socket is not alloced"; + return; + } + +// qDebug() << "check client connect"; + if (m_connected == 1) + { + if (m_localip.isEmpty() == false) + { + m_pClientSocket->bindAddrAndPort(m_localip, m_localport); + } + m_pClientSocket->abort(); + m_pClientSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); + m_pClientSocket->connectToHost(m_serverip, m_serverport); + int rslt = m_pClientSocket->waitForConnected(2000); + if (rslt == 0) + { + + } + /* + qDebug("bind connect and waitForConnected 2000, rslt=%d", rslt); + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport; + */ + m_connected = 2; + } + else if (m_connected != 0) + { + switch(m_pClientSocket->state()) + { + case QAbstractSocket::ConnectedState: + { + if (m_connected != 3) + { + /* + qDebug() << "net State is Connected"; + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + */ + m_connected = 3; // 检测连接状态 + } + + break; + } + case QAbstractSocket::ConnectingState: + { + if (m_connected != 2) + { + qDebug() << "net State is Connecting"; + // qDebug() << "localip=" << m_localip << "localport=" << m_localport; + } + m_connected = 2; + break; + } + case QAbstractSocket::UnconnectedState: + { + if (m_connected != 1) + { + // qDebug() << "net State is unconnected"; + // qDebug() << "localip=" << m_localip << "localport=" << m_localport; + } + m_connected = 1; + break; + } + default: + { + /* + QAbstractSocket::HostLookupState + QAbstractSocket::BoundState + QAbstractSocket::ListeningState + QAbstractSocket::ClosingState + */ + { + qDebug("net State is %d\r\n", m_pClientSocket->state()); + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport; + } + m_connected = 1; + } + } + } + else + { + + } + + if (m_connected == 3) // 已连接 + { + if (m_detect == 1) + { + // qDebug() << "Machine " << QThread::currentThread(); + m_detect = 0; + emit(siDetectHost()); + // qDebug() << "after send SiDetectHost "; + } + } + + emit (siConnectSta(m_connected)); // 网络连接信号 +} + +void TcpClient::detectStatus(int sta) +{ + // qDebug("host detect sta=%d", sta); + + m_detect = 1; + if (sta == 1) // 网络已断开 + { + qDebug("disconnect ClientSocket by detect"); + m_pClientSocket->disconnectFromHost(); +// m_pClientSocket->waitForDisconnected(); + m_pClientSocket->close(); + m_connected = 1; + } + else if (sta == 2) // 网络连接还在 + { + + } + else + { + + } +} + +void TcpClient::receiveServerData() +{ + if (m_pClientSocket != NULL) + { + QByteArray tmpDat; + tmpDat = m_pClientSocket->readAll(); // 读取 +// qDebug("ReceiveServerData, size = %d", tmpDat.size()); +// PrintAsHex(&tmpDat); + + emit(siReceiveData(tmpDat)); // 发送收到数据信号 + } +} + +void TcpClient::displaySocketError(QAbstractSocket::SocketError err) +{ + QString errinfo; + + errinfo.sprintf("Err: code=%d, errorString=", err); + errinfo += m_pClientSocket->errorString(); + +// qDebug() << errinfo; + + emit(siConnectErr(errinfo)); // 网络错误信息 +} + +void TcpClient::netStateChanged(QAbstractSocket::SocketState sta) +{ + switch (sta) + { + /* + case UnconnectedState: + case HostLookupState: + case ConnectingState: + case ConnectedState: + case BoundState: + case ListeningState: + case ClosingStat: + */ + default: + break; + } + +} +void TcpClient::hostFound() +{ + qDebug("found host"); + + +} + + +#if(0) +//------------------------------------------------------- +TcpConnectDetect::TcpConnectDetect(QObject *parent) : + QObject(parent), + m_pDetectSocket(NULL), + m_localip(DEF_LOCAL_IP), + m_localport(DEF_LOCAL_PORT), + m_serverip(DEF_SERVER_IP), + m_serverport(DEF_SERVER_PORT) +{ +} + +TcpConnectDetect::~TcpConnectDetect() +{ + if (m_pDetectSocket == NULL) + { + m_pDetectSocket->disconnectFromHost(); + m_pDetectSocket->waitForDisconnected(); + m_pDetectSocket->close(); + delete m_pDetectSocket; + } +} + +void TcpConnectDetect::detectStart() +{ + qDebug("TcpConnectDetect start"); + if (m_pDetectSocket == NULL) + { + m_pDetectSocket = new QBindTcpSocket; + } +} + +int TcpConnectDetect::connectDetect() +{ + int connectsta = 0; + int rslt; + + // qDebug() << "TcpConnectDetect " << QThread::currentThread(); + + if (m_pDetectSocket == NULL) + { + return 0; + } + if (m_localip.isEmpty() == false) + { + m_pDetectSocket->bindAddrAndPort(m_localip, m_localport); + } + m_pDetectSocket->abort(); + m_pDetectSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); + m_pDetectSocket->connectToHost(m_serverip, m_serverport); + + do + { + rslt = m_pDetectSocket->waitForConnected(4000); // 等待连接 + + qDebug("bind Detect connect rslt=%d", rslt); + qDebug() << "localip=" << m_localip << "localport=" << m_localport; + qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport; + + switch(m_pDetectSocket->state()) + { + case QAbstractSocket::ConnectedState: + { + // 如果连接上,说明 m_pClientSocket 连接已经无效, 需要断开重新连接 + // 先断开测试连接 + m_pDetectSocket->disconnectFromHost(); + m_pDetectSocket->waitForDisconnected(); + connectsta = 1; + // 发送断开主连接的信号 + qDebug() << "detect is Connected, disconnect all"; + + break; + } + case QAbstractSocket::UnconnectedState: + { + // qDebug() << "detect is Unconnected err=" << m_pDetectSocket->error() << ", info:" << m_pDetectSocket->errorString(); + + switch (m_pDetectSocket->error()) + { + case QAbstractSocket::SocketTimeoutError: // 连接超时,说明已经断开 + case QAbstractSocket::NetworkError: // 网络错误, 主机不可连接, 可能已经断开 + { + qDebug() << "detect is timout, disconnect all"; + connectsta = 1; + // 发送断开主连接的信号 + break; + } + case QAbstractSocket::ConnectionRefusedError: // 拒绝连接, 说明连接还在 + { + connectsta = 2; + // qDebug() << "Connection Refused, old connect is alive"; + break; + } + /* + case QAbstractSocket::RemoteHostClosedError: + case QAbstractSocket::HostNotFoundError: + case QAbstractSocket::SocketAccessError: + case QAbstractSocket::SocketResourceError: + case QAbstractSocket::SocketTimeoutError: + case QAbstractSocket::DatagramTooLargeError: + case QAbstractSocket::AddressInUseError: + case QAbstractSocket::SocketAddressNotAvailableError: + case QAbstractSocket::UnsupportedSocketOperationError: + case QAbstractSocket::UnfinishedSocketOperationError: + case QAbstractSocket::ProxyAuthenticationRequiredError: + case QAbstractSocket::SslHandshakeFailedError: + case QAbstractSocket::ProxyConnectionRefusedError: + case QAbstractSocket::ProxyConnectionClosedError: + case QAbstractSocket::ProxyConnectionTimeoutError: + case QAbstractSocket::ProxyNotFoundError: + case QAbstractSocket::ProxyProtocolError: + case QAbstractSocket::UnknownSocketError: + */ + default: + { + // 继续检测 + connectsta = 2; + qDebug() << " retry"; + break; + } + } // 错误处理结束 + } + case QAbstractSocket::ConnectingState: + { + // qDebug() << "detect is Connecting"; + // qDebug() << "localip=" << m_localip << "localport=" << m_localport; + // 继续等待 + break; + } + case QAbstractSocket::HostLookupState: + case QAbstractSocket::BoundState: + case QAbstractSocket::ListeningState: + case QAbstractSocket::ClosingState: + default: + { + // 继续等待 + qDebug("detect sta is %d\r\n", m_pDetectSocket->state()); + break; + } + } + + if (connectsta != 0) + { + break; + } + + }while(1); + + + m_pDetectSocket->close(); + + // 发送本次测试连接的状态信号 + emit(siConnectSta(connectsta)); + return connectsta; +} + +void TcpConnectDetect::setIpAndPort(QString localip, quint16 localport, QString serverip, quint16 serverport) +{ + m_localip = localip; + m_localport = localport; + m_serverip = serverip; + m_serverport = serverport; +} +#endif + + + + + + diff --git a/machine/tcp/tcpclient.h b/machine/tcp/tcpclient.h new file mode 100644 index 0000000..e3957a8 --- /dev/null +++ b/machine/tcp/tcpclient.h @@ -0,0 +1,97 @@ +#ifndef TCPCLIENT_H +#define TCPCLIENT_H + +//#include +#include +#include +#include +#include +#include +//#include + +#include "qbindtcpsocket.h" + +class ConnectDetectThread; + + +class TcpClient : public QObject +{ + Q_OBJECT +public: + explicit TcpClient(QObject *parent = NULL); + virtual ~TcpClient(); + +public: + void setIpAndPort(QString serverIp, quint16 serverPort, QString localIp, quint16 localPort); +signals: + void siConnectSta(int sta); // 网络连接信号 + void siConnectErr(QString errinfo); // 网络错误信息 + void siReceiveData(QByteArray dat); // 收到数据包信号 +signals: + void siDetectHost(void); +public: + + +public slots: + void slotSendData(QByteArray dat); // 发送数据的槽 + void connectToServer();//连接到服务器 + void disConnectFromServer(); + void detectStatus(int); +public: + +private slots: + void connectCheck(); + void receiveServerData(); + void displaySocketError(QAbstractSocket::SocketError err); + void netStateChanged(QAbstractSocket::SocketState sta); + void hostFound(); + +private: + QBindTcpSocket * m_pClientSocket;//客户端 + QTimer * m_pConnectCheckTimer; + +public: + int m_connected; // 连接状态; 0, 初始化; 1, 未连接; 2, 连接中; 3, 已连接 + +private: + TcpConnectDetect * m_pConnectDetect; + int m_detect; // 连接测试状态 + +private: + QString m_localip; + quint16 m_localport; + QString m_serverip; + quint16 m_serverport; +}; + +#if(0) +class TcpConnectDetect : public QObject +{ + Q_OBJECT +public: + explicit TcpConnectDetect(QObject *parent = NULL); + virtual ~TcpConnectDetect(); + +signals: + void siConnectSta(int sta); // 网络连接信号 +public: + +public slots: + void detectStart(); + int connectDetect(); + +private: + QBindTcpSocket * m_pDetectSocket; + +public: + void setIpAndPort(QString localip, quint16 localport, QString serverip, quint16 serverport); + +private: + QString m_localip; + quint16 m_localport; + QString m_serverip; + quint16 m_serverport; +}; +#endif + +#endif // TCPCLIENT_H diff --git a/machine/tcp/tcpserver.cpp b/machine/tcp/tcpserver.cpp new file mode 100644 index 0000000..bbac22d --- /dev/null +++ b/machine/tcp/tcpserver.cpp @@ -0,0 +1,123 @@ +#include "tcpserver.h" + +TcpServer::TcpServer(QObject *parent) : QObject(parent) +{ + m_server = NULL; + m_curSocket = NULL; + m_clientList.clear(); +} + +TcpServer::~TcpServer() +{ + if(m_server != NULL) + { + delete m_server; + m_server = NULL; + } + + if(m_curSocket != NULL) + { + delete m_curSocket; + m_curSocket = NULL; + } +} + +void TcpServer::slotNewConnect() +{ + m_curSocket = m_server->nextPendingConnection();//获取客户端连接 + //获取远端客户端ip和端口号 + QString ip = m_curSocket->peerAddress().toString(); + int port = m_curSocket->peerPort(); + emit siNewClient(ip, port, 1); + + CTcpClient client; + client.ip = ip; + client.port = port; + client.socket = m_curSocket; + m_clientList.append(client); + + connect(m_curSocket, &QTcpSocket::readyRead, this, &TcpServer::slotRecvData); + connect(m_curSocket, &QTcpSocket::disconnected, this, &TcpServer::slotDisConnect); +} + +void TcpServer::slotDisConnect() +{ + for (QList::iterator it = m_clientList.begin(); it != m_clientList.end(); ++it) + { + if (QAbstractSocket::UnconnectedState == it->socket->state()) + { + emit siDisConncet(it->ip, it->port, -1); + it = m_clientList.erase(it, it + 1); + it--; + } + } +} + +void TcpServer::slotInit() +{ + m_server = new QTcpServer(); + if (!m_server->isListening()) + { + m_server->listen(QHostAddress::AnyIPv4, PORT);//监听IPV4的任意地址 + connect(m_server, &QTcpServer::newConnection, this, &TcpServer::slotNewConnect); + } +} + +void TcpServer::slotRecvData() +{ + for (QList::iterator it = m_clientList.begin(); it != m_clientList.end(); ++it) + { + if ((it->socket)->isReadable()) + { + QByteArray buf = (it->socket)->readAll(); + if (!buf.isEmpty()) + { + //获取客户端socket的ip和端口号 + QString ip = (it->socket)->peerAddress().toString(); + int port = (it->socket)->peerPort(); + CommMsg msg; + msg.buf = buf; + msg.ip = ip; + msg.port = port; + emit siNewMsg(msg); + } + } + } +} + +void TcpServer::slotSendData(CommMsg msg) +{ + QString ip = msg.ip; + int port = msg.port; + for (QList::iterator it = m_clientList.begin(); it != m_clientList.end(); ++it) + { + if (it->ip == ip && it->port == port) + { + it->socket->write(msg.buf); + } + } +} + +void TcpServer::slotStopMonitor() +{ + if (m_server->isListening()) + { + m_server->disconnect(); + m_server->close(); + m_server->deleteLater(); + m_server = NULL; + } +} + +void TcpServer::slotStartMonitor() +{ + if(m_server == NULL) + { + m_server = new QTcpServer(); + } + if (!m_server->isListening()) + { + m_server->listen(QHostAddress::AnyIPv4, PORT);//监听IPV4的任意地址 + connect(m_server, &QTcpServer::newConnection, this, &TcpServer::slotNewConnect); + } +} diff --git a/machine/tcp/tcpserver.h b/machine/tcp/tcpserver.h new file mode 100644 index 0000000..1bd48e5 --- /dev/null +++ b/machine/tcp/tcpserver.h @@ -0,0 +1,55 @@ +#ifndef TCPSERVER_H +#define TCPSERVER_H + +#include +#include +#include + +#define PORT 5000 + +struct CommMsg +{ + QString ip; + int port; + QByteArray buf; + int size; //buf的字节数 +}; + +struct CTcpClient +{ + QString ip; + int port; + QTcpSocket* socket; +}; + +class TcpServer : public QObject +{ + Q_OBJECT +public: + explicit TcpServer(QObject *parent = nullptr); + ~TcpServer(); + +private: + QTcpServer *m_server; + QList m_clientList; + QTcpSocket *m_curSocket; + +private slots: + void slotNewConnect();//新的客户端连接 + void slotDisConnect(); //客户端断开连接 + +signals: + void siNewClient(const QString ip, const int port, int add); //新的客户端 + void siNewMsg(const CommMsg dat); //发送给客户端的消息 + void siDisConncet(const QString ip, const int port, int red); //客户端断开连接 + +public slots: + void slotInit(); + void slotRecvData(); + void slotSendData(CommMsg msg); + void slotStopMonitor(); + void slotStartMonitor(); + +}; + +#endif // TCPSERVER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..78f03e2 --- /dev/null +++ b/main.cpp @@ -0,0 +1,88 @@ +#include +#include + +#define _IN_MAIN_CPP +#include "main.h" +#include "mainwindow.h" + +int main(int argc,char *argv[]) +{ + QApplication app(argc, argv); + + //支持中文编码 + QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK")); + + //下位机通讯 + //上次所连接机器的IP + QDir apppath(qApp->applicationDirPath()); + QString configfile; + configfile = apppath.path() + apppath.separator() + "config.ini"; + QSettings settings(configfile, QSettings::IniFormat); + + QString localIp = "192.168.16.41"; + quint16 localPort = 5001; + + QFile iniFile(configfile); + if(!iniFile.exists())//配置文件不存在 + { + settings.setValue("Local/ip","192.168.16.41"); + settings.setValue("Local/port",5001); + } + else + { + //本地IP和端口 + localIp = settings.value("Local/ip").toString(); + localPort = settings.value("Local/port").toInt(); + } + + g_machineList.clear(); + + int num = 0; + for(int i = 1; i <= MACHINE_NUM; i++) + { + QString str = "MachineNo" + QString::number(i); + QString strKey = str + "/name"; + bool bl = settings.contains(strKey); + if(bl == true) + { + num++; + //建立连接 + QString mcIp = settings.value(str+"/ip").toString(); + quint16 mcPort = settings.value(str+"/port").toInt(); + QString mcName = settings.value(str+"/name").toString(); + + Machine *pMachine = new Machine(); //建立连接 + pMachine->setIpAndPort(mcName,mcIp,mcPort,localIp,localPort);//设置IP和端口 + pMachine->startCommunication(); + McPrintInfo mcf; + mcf.m_mcNum = num; + mcf.m_mcName = mcName; + mcf.m_ip = mcIp; + mcf.m_port = mcPort; + pMachine->m_mcPrintInfo = mcf; + g_machineList.append(pMachine); + } + } + + MainWindow mainWi; + mainWi.initAllWinForm(); + mainWi.show(); + +#if(0) +#if(1) + //有机器连接时才加载自动绘图目录 + if(machineList.size() > 0) + { + mainWi.loadAutoPrintDirFiles(); + } +#else + if(machineList.size() > 0) + { + QtConcurrent::run(&mainWi, &MainWindow::loadAutoPrintDirFiles);//并发线程的使用,为了避免同时加载窗体和加载文件时的窗体卡顿 + } +#endif +#endif + + app.exec(); + return 0; +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..46e4cd1 --- /dev/null +++ b/main.h @@ -0,0 +1,26 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include "machine/machine.h" + +#define BLOCK_MM 300 //每块对应的毫米数 +#define MACHINE_NUM 255 //连接机器最大数量值 + +//语言 +enum Language +{ + LANGUAGE_CHINESE = 1, + LANGUAGE_ENGLISH = 2 +}; + +#ifdef _IN_MAIN_CPP +QList g_machineList; +int g_language; +#else +extern QList g_machineList; +extern int g_language; +#endif + +#endif // MAIN_H diff --git a/mainwidget.ui b/mainwidget.ui new file mode 100644 index 0000000..de18f75 --- /dev/null +++ b/mainwidget.ui @@ -0,0 +1,24 @@ + + + MainWidget + + + + 0 + 0 + 800 + 480 + + + + III PlotCenter + + + + File(F) + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..3854bd5 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,1499 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + this->showMaximized(); + iniViewModel(); + qRegisterMetaType >("QVector");//对自定义类型注册 +} + +MainWindow::~MainWindow() +{ + if(m_autoPrintLoadThread.isRunning() == true) + { + while(m_autoPrintLoadThread.isRunning()) + { + m_breakAutoLoadThread = 1;//暂停、取消线程的运行 + } + } + + if(m_drawingSetDlg != NULL) + { + delete m_drawingSetDlg; + } + + if(m_plotterSetDlg!= NULL) + { + delete m_plotterSetDlg; + } + + if(m_historyDlg != NULL) + { + delete m_historyDlg; + } + + if(m_printViewWi != NULL) + { + delete m_printViewWi; + } + + if(m_sendTimer != NULL) + { + delete m_sendTimer; + } + + if(m_pTimer != NULL) + { + delete m_pTimer; + } + + if(m_printInfoDlg != NULL) + { + delete m_printInfoDlg; + } + + if(m_preView != NULL) + { + delete m_preView; + m_preView = NULL; + } + + for(int i = 0; i < g_machineList.size(); i++) + { + g_machineList[i]->m_mcPrintInfo.clear(); + } + + delete ui; +} + +void MainWindow::closeEvent(QCloseEvent *e) +{ + e->accept(); +} + +void MainWindow::reflushPreview(int row) +{ + if(row < 0) + { + return; + } + + if(m_curFileRow >= g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size()) + { + m_preView->cleanView(); + m_tabelViewModelFile->removeRows(0,m_tabelViewModelFile->rowCount()); + return; + } + + if(m_curFileRow < 0) + { + return; + } + + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow].m_selectBlockNum = 0;//上次查看的文件的块数选择置为0 + m_curBlockRow = -1; + ui->tableView_fileList->selectRow(row); + + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_creatBmpFlag != 1) + { + ui->tableView_fileList->setEnabled(false); + ui->tableView_Connection->setEnabled(false); + + //生成绘制图 + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_pic = creatFilePicture(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row]); + + //将picture保存为多个宽度为2400像素的bmp + int num = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_pic.width() / PIXMAPWIDTH; + int lwidth = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_pic.width() % PIXMAPWIDTH; + if(lwidth != 0) + { + num +=1; + } + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_totalBlocks = num; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_leaveBlockNum = num;//剩余打印块数 + + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_creatBmpFlag = 1; + ui->tableView_fileList->setEnabled(true); + ui->tableView_Connection->setEnabled(true); + } + + //刷新图形 + QPicture pic = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row].m_pic; + m_preView->cleanView(); + m_preView->swithView(pic); + m_curFilesInfo = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[row]; +} + +void MainWindow::reflushMcFileInfo() +{ + ui->label_fileTotalVal->setText(QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileNums)); + ui->label_fileTotalLenthVal->setText(QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileTotalLength)+"mm"); +} + +void MainWindow::changeRowData(int move) +{ + int row = m_curFileRow; + if(NULL == m_tabelViewModelFile || row < 0 || row > m_tabelViewModelFile->rowCount()-1) + { + return ; + } + + if(move == 1) + { + //下移需要判断最后一行,不移动 + if(row == m_tabelViewModelFile->rowCount()-1) + { + return ; + } + } + else if(move == -1) + { + //上移需要判断是否第一行,不移动 + if(row == 0) + { + return ; + } + } + g_machineList[m_curMcIdx]->moveFilePrintDat(m_curFileRow,move); + QList listItem = m_tabelViewModelFile->takeRow(row); + m_curFileRow = row + move; + m_tabelViewModelFile->insertRow(m_curFileRow,listItem); + ui->tableView_fileList->selectRow(m_curFileRow); +} + +bool MainWindow::deleteDir(QString path) +{ + if (path.isEmpty()) + { + return false; + } + QDir dir(path); + if(!dir.exists()) + { + return true; + } + dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); //设置过滤 + QFileInfoList fileList = dir.entryInfoList(); // 获取所有的文件信息 + foreach (QFileInfo file, fileList) + { + //遍历文件信息 + if (file.isFile()) + { + // 是文件,删除 + file.dir().remove(file.fileName()); + } + else + { + // 递归删除 + deleteDir(file.absoluteFilePath()); + } + } + return dir.rmdir(dir.absolutePath()); // 删除文件夹 +} + +void MainWindow::setButtonEnable(bool bl) +{ + ui->actionOpen_File->setEnabled(bl); + ui->actionOpen_Image->setEnabled(bl); + ui->actiontest1_plt->setEnabled(bl); + ui->actionStart->setEnabled(bl); + ui->actionPause->setEnabled(bl); + ui->actionDelete->setEnabled(bl); + ui->actionDrawing_Setting->setEnabled(bl); + ui->actionPlotter_Setting->setEnabled(bl); + ui->actionOpenFileIcon->setEnabled(bl); + ui->actionOpenImageIcon->setEnabled(bl); + ui->actionStartIcon->setEnabled(bl); + ui->actionPauseIcon->setEnabled(bl); + ui->actionDrawingSetIcon->setEnabled(bl); + ui->pushButton_up->setEnabled(bl); + ui->pushButton_down->setEnabled(bl); + ui->pushButton_delete->setEnabled(bl); + ui->pushButton_preview->setEnabled(bl); +} + +void MainWindow::startCreatBmpAndSend(int mcIdx) +{ + int mcBegIdx, mcEndIdx; + mcBegIdx = mcEndIdx = 0; + + //自动打印时mcIdx为-1 + //mcIdx = -1; + + if(mcIdx == -1) + { + mcBegIdx = 0; + mcEndIdx = g_machineList.size(); + } + else + { + mcBegIdx = mcIdx; + mcEndIdx = mcIdx + 1; + } + + for(int i = mcBegIdx; i < mcEndIdx; i++) + { + if(m_workState == WORK_PAUSE) + { + return; + } + //生成bmp块 + QDir printDir(m_printPath);//总的打印目录 + if(!printDir.exists()) + { + printDir.mkdir(m_printPath); + } + + QString mcFile = m_printPath + printDir.separator() + PRINTMCDIR + QString::number(g_machineList[i]->m_mcPrintInfo.m_mcNum); + QDir mcDir(mcFile);//对应每台机器打印目录 + if(!mcDir.exists()) + { + mcDir.mkdir(mcFile); + } + g_machineList[i]->creatPrintDat(m_curFileRow); + } +} + +QPicture MainWindow::creatFilePicture(McFilesInfo & mcFileInfo, s16 penWidth) +{ + //将图片画在picture上 + QPicture pic; + QPen pen; + if(mcFileInfo.m_fileType == TYPE_FILE) + { + pen.setWidth(penWidth);//设置笔号 + } + else if(mcFileInfo.m_fileType == TYPE_IMAGE) + { + pen.setWidth(1);//设置笔号 + } + pen.setColor(QColor(Qt::black)); + + QPainter painter; + painter.begin(&pic); + painter.setPen(pen); + + if(mcFileInfo.m_fileType == TYPE_IMAGE) + { + painter.drawPixmap(0,0,mcFileInfo.m_pixmap); + } + else + { + CBitmapInfo bitmapInfo; + QPainterPath painterPath; + QRect rect = mcFileInfo.m_marker.GetRect(); + int minX = rect.left(); + int minY = rect.top(); + int maxY = rect.bottom(); + + int nLineCount = mcFileInfo.m_marker.m_listPolyline.size(); + for(int i = 0; i < nLineCount; i++) + { + CRPPolyline polyLine = mcFileInfo.m_marker.m_listPolyline.at(i); + int type = polyLine.m_nDrawingType; + // if(polyLine.m_nDrawingType == 3)//文字 + // { + // CRPText text = polyLine.m_text; + // } + + if(type == 0)//直线 + { + int nPointCount = polyLine.m_listPoint.size(); + for(int j = 0; j < nPointCount; j++) + { + double x = (polyLine.m_listPoint.at(j).x() - minX)/(double)M_IDPMM*MMPIXELY; + double y = ((0 - (polyLine.m_listPoint.at(j).y() - minY))+(maxY-minY))/(double)M_IDPMM*MMPIXELY; + QPointF point(x,y); + + if(j == 0) + { + painterPath.moveTo(point); + } + else + { + painterPath.lineTo(point); + } + } + } + else if(type == 1)//位图 + { + bitmapInfo = polyLine.m_bitmapInfo; + int x = bitmapInfo.m_ptAbPostLU.x(); + int y = bitmapInfo.m_ptAbPostLU.y(); + + int nx = (x - minX)/M_IDPMM*MMPIXELY; + int ny = ((0 - (y - minY))+(maxY-minY))/M_IDPMM*MMPIXELY; + + bitmapInfo.m_ptAbPostLU.setX(nx); + bitmapInfo.m_ptAbPostLU.setY(ny); + } + } + + if(painterPath.isEmpty()) + { + qDebug()<<"painterPath.isEmpty"; + } + + painter.drawPath(painterPath); + if(bitmapInfo.m_iBytes > 0)//有位图 + { + //bitmapInfo.m_pBitmap.save("D:\\1.bmp"); + painter.drawPixmap(bitmapInfo.m_ptAbPostLU.x(),bitmapInfo.m_ptAbPostLU.y(),bitmapInfo.m_pBitmap); + } + } + + painter.end(); + return pic; +} + +void MainWindow::refConnectUi() +{ + for(int i = 0; i < g_machineList.size(); i++) + { + refConnectUi(g_machineList[i], g_machineList[i]->m_mcPrintInfo.m_mcConnState, i); + } +} + +//刷新连接状态 +void MainWindow::refConnectUi(Machine *pMachine, int &linkSta, int idx) +{ + if (pMachine != NULL) + { + if (linkSta != pMachine->isConnected() || + pMachine->isConnected() == Connectting) + { + linkSta = pMachine->isConnected();//获取连接状态 + QString strConn; + if (linkSta == Connectting)//连接中... + { + strConn = tr("Connnecting...");//连接中... + } + else if (linkSta == Connected)//已连接 + { + strConn = tr("Connected");//已连接 + } + else//未连接 + { + strConn = tr("NotConnected");//未连接 + } + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(idx, CONN_COLUMN_MCCONSTATE),strConn); + } + } +} + +void MainWindow::refreshMcListShow() +{ + if(g_machineList.size() <= 0) + { + ui->menuFile_F->setEnabled(false); + return; + } + for(int i = 0; i < g_machineList.size(); i++) + { + int row = m_tabelViewModelConn->rowCount();//当前表格的行数 + m_tabelViewModelConn->insertRow(row);//在最后一行的后面插入一行 + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row, CONN_COLUMN_MCNAME),g_machineList[i]->m_mcPrintInfo.m_mcName); + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCIP),g_machineList[i]->m_mcPrintInfo.m_ip); + + QString strConn = tr("NotConnected");//未连接 + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCCONSTATE),strConn); + + QString str; + if(g_machineList[i]->m_mcPrintInfo.m_mcWorkState == NotBusy) + { + str = tr("Idle");//空闲中 + } + else if(g_machineList[i]->m_mcPrintInfo.m_mcWorkState == Busying) + { + str = tr("Working");//工作中 + } + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCWORKSTATE),str); + QString strPro = QString::number(g_machineList[i]->m_mcPrintInfo.m_mcSendProgress) + "%"; + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCPROGRESS),strPro); + + connect(g_machineList[i], SIGNAL(siDeleteFileFinish()), + this, SLOT(slotDeleteFileFinish())); // 发送数据的槽 + } + // m_curMcIdx = 0; + // ui->tableView_Connection->selectRow(m_curMcIdx); +} + +void MainWindow::refreshOneMcShow(int row,int idx) +{ + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row, CONN_COLUMN_MCNAME),g_machineList[idx]->m_mcPrintInfo.m_mcName); + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCIP),g_machineList[idx]->m_mcPrintInfo.m_ip); + + QString strConn = tr("NotConnected");//未连接 + if(g_machineList[idx]->m_mcPrintInfo.m_mcWorkState == Connectting) + { + strConn = tr("Connnecting...");//连接中... + } + else if(g_machineList[idx]->m_mcPrintInfo.m_mcWorkState == Connected) + { + strConn = tr("Connected");//已连接 + } + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCCONSTATE),strConn); + + QString str; + if(g_machineList[idx]->m_mcPrintInfo.m_mcWorkState == NotBusy) + { + str = tr("Idle");//空闲中 + } + else if(g_machineList[idx]->m_mcPrintInfo.m_mcWorkState == Busying) + { + str = tr("Working");//工作中 + } + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCWORKSTATE),str); + QString strPro = QString::number(g_machineList[idx]->m_mcPrintInfo.m_mcSendProgress) + "%"; + m_tabelViewModelConn->setData(m_tabelViewModelConn->index(row,CONN_COLUMN_MCPROGRESS),strPro); +} + +int MainWindow::refreshMcFileListShow(int idx) +{ + if(m_autoPrintLoadThread.isRunning() == true) + { + m_breakAutoLoadThread = 1;//暂停、取消线程的运行 + while(m_autoPrintLoadThread.isRunning() == true) + { + //等待线程结束 + } + } + + m_curMcIdx = idx; + m_tabelViewModelFile->removeRows(0,m_tabelViewModelFile->rowCount()); + m_preView->cleanView(); + + QString iniName = "MachineNo" + QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_mcNum) + ".ini"; + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + iniName; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + QString dirPath = setting.value("AutoPrintDir/fileDir").toString(); + QDir dir(dirPath); + //存在自动绘图目录或上次未打印完成文件时首次点击先加载文件 + if(dir.exists() && dirPath.length() != 0 && g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag < 0) + { + //并发线程的使用,为了避免同时加载窗体和加载文件时的窗体卡顿 + m_autoPrintLoadThread = QtConcurrent::run(this,this->slotLoadAutoPrintFiles); + return 0; + } + else + { + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag = 1; + QList filesList = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList; + int size = filesList.size(); + + for(int i = 0; i < size; i++) + { + m_tabelViewModelFile->insertRow(i);//在最后一行的后面插入一行 + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_FILENAME),filesList[i].m_fileName); + + QRect rect = filesList[i].m_fileRect; + + QString length = QString::number((rect.right() - rect.left())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_LENGTH),length); + + QString width = QString::number((rect.bottom() - rect.top())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_WIDTH),width); + + QString start = QString::number(filesList[i].m_startPoint)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_START),start); + + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_PRINTEDLENGTH),"0mm"); + + QString number = QString::number(filesList[i].m_printNum); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_NUMBERS),number); + + //QString state = tr("Waitting"); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_STATE),filesList[i].m_printState); + + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(i,COLUMN_FILEPATH),filesList[i].m_filePath); + } + + reflushMcFileInfo(); + qDebug()<<"reflushMcFileInfo();"; + m_curFileRow = 0; + ui->tableView_fileList->selectRow(m_curFileRow);//选中 + reflushPreview(m_curFileRow); + } + return 0; +} + +void MainWindow::loadAutoPrintDirFiles() +{ + //并发线程的使用,为了避免同时加载窗体和加载文件时的窗体卡顿 + m_autoPrintLoadThread = QtConcurrent::run(this,this->slotLoadAutoPrintFiles); +} + +//初始化所有窗体 +void MainWindow::initAllWinForm() +{ + refreshMcListShow(); + + m_curMcIdx = -1; + m_curFileRow = -1; + m_curPrintFileIdx = -1; + m_curBlockRow = -1; + m_preView = NULL; + + m_workState = PAUSE; + m_printMode = NOAUTOPRINT; + m_breakAutoLoadThread = 0; + + QDir apppath(qApp->applicationDirPath()); + m_printPath = apppath.path() + apppath.separator() + "print"; + + m_preView = new MyGraphicsView(); + ui->verticalLayout_drawing->addWidget(m_preView); + + m_drawingSetDlg= new DrawingSetDialog(); + m_plotterSetDlg = new PlotterSetDialog(); + m_historyDlg = new HistoryDialog(); + m_printViewWi = new PrintViewWindow(this); + connect(m_printViewWi,SIGNAL(siAddNewFile(int)),this,SLOT(slotAddNewFileToList(int))); + + m_printInfoDlg = new PrintInfoDialog(); + + m_sendTimer = new QTimer(this); + m_sendTimer->setInterval(100); // 设置定时间隔100毫秒 + connect(m_sendTimer, SIGNAL(timeout()), this, SLOT(onSendTimer())); + m_sendTimer->start(); + + //定时器 + m_pTimer = new QTimer(this); + m_pTimer->setInterval(1000); // 设置定时间隔1秒 + connect(m_pTimer, SIGNAL(timeout()), this, SLOT(onOneSecondTimer())); + m_pTimer->start(); + + m_drawingSetDlg->hide(); + m_plotterSetDlg->hide(); + m_historyDlg->hide(); + m_printViewWi->hide(); + m_printInfoDlg->hide(); + + //删除位图文件夹 + deleteDir(m_printPath); + //setButtonEnable(false); +} + +void MainWindow::iniViewModel() +{ + //QTabelView + m_tabelViewModelFile = new QStandardItemModel(0, COLUMN_NUM, ui->tableView_fileList); + QStringList header; //QString类型的List容器 + header<setHorizontalHeaderLabels(header); + ui->tableView_fileList->setModel(m_tabelViewModelFile); + ui->tableView_fileList->setSelectionBehavior(QAbstractItemView::SelectRows);//单击选择一行 + ui->tableView_fileList->setEditTriggers(QAbstractItemView::NoEditTriggers);//每行不可编辑 + ui->tableView_fileList->setSelectionMode(QAbstractItemView::SingleSelection);//只能选择一行 + ui->tableView_fileList->setColumnWidth(0,COLUMN_COLWIDTH+100);//设置列宽 + for(int i = 1; i < COLUMN_NUM-1; i++) + { + ui->tableView_fileList->setColumnWidth(i,COLUMN_COLWIDTH);//设置列宽 + } + ui->tableView_fileList->setColumnWidth(COLUMN_NUM-1,COLUMN_COLWIDTH+200);//设置列宽 + ui->tableView_fileList->horizontalHeader()->setHighlightSections(false);//设置表头字体不变粗 + //ui->tableView_fileList->horizontalHeader()->setStyleSheet("border-bottom-width: 0.5px;border-style: outset;border-color: rgb(229,229,229);");//表头和第一行之间加分割线 + + ui->tableView_fileList->setContextMenuPolicy(Qt::CustomContextMenu);//设置右击菜单 + connect(ui->tableView_fileList,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(slotFileListMenu(QPoint))); + + //建立数据模型对象空间并指定父对象 + m_tabelViewModelConn = new QStandardItemModel(0, CONN_COLUMN_NUM, ui->tableView_Connection); + QStringList headerConn; //QString类型的List容器 + headerConn<setHorizontalHeaderLabels(headerConn); + ui->tableView_Connection->setModel(m_tabelViewModelConn); + ui->tableView_Connection->setSelectionBehavior(QAbstractItemView::SelectRows);//单击选择一行 + ui->tableView_Connection->setEditTriggers(QAbstractItemView::NoEditTriggers);//每行不可编辑 + ui->tableView_Connection->setSelectionMode(QAbstractItemView::SingleSelection);//只能选择一行 + for(int i = 0; i < CONN_COLUMN_NUM; i++) + { + ui->tableView_Connection->setColumnWidth(i,CONN_COLUMN_COLWIDTH);//设置列宽 + } + ui->tableView_Connection->horizontalHeader()->setHighlightSections(false);//设置表头字体不变粗 + ui->tableView_Connection->setContextMenuPolicy(Qt::CustomContextMenu);//设置右击菜单 + connect(ui->tableView_Connection,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(slotMcListMenu(QPoint))); +} + +void MainWindow::slotAddNewFileToList(int newFlag) +{ + if(newFlag == 0)//非新文件 + { + int start = m_printViewWi->getStartPoint(); + int number = m_printViewWi->getPrintNumber(); + + int oldStart = m_tabelViewModelFile->item(m_curFileRow,COLUMN_START)->text().remove("mm").toInt(); + int oldNumber = m_tabelViewModelFile->item(m_curFileRow,COLUMN_NUMBERS)->text().toInt(); + + if(start != oldStart) + { + m_tabelViewModelFile->item(m_curFileRow,COLUMN_START)->setText(QString::number(start)+"mm"); + } + if(number != oldNumber) + { + m_tabelViewModelFile->item(m_curFileRow,COLUMN_NUMBERS)->setText(QString::number(number)); + } + + m_curFilesInfo.m_printNum = number; + m_curFilesInfo.m_startPoint = start; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow] = m_curFilesInfo; + } + else //新文件 + { + int row = m_tabelViewModelFile->rowCount();//当前表格的行数 + m_tabelViewModelFile->insertRow(row);//在最后一行的后面插入一行 + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_FILENAME),m_curFilesInfo.m_fileName); + + QRect rect = m_curFilesInfo.m_fileRect; + + QString length = QString::number((rect.right() - rect.left())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_LENGTH),length); + + QString width = QString::number((rect.bottom() - rect.top())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_WIDTH),width); + + QString start = QString::number(m_printViewWi->getStartPoint())+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_START),start); + + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_PRINTEDLENGTH),"0mm"); + + QString number = QString::number(m_printViewWi->getPrintNumber()); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_NUMBERS),number); + + QString state = tr("Waitting"); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_STATE),state); + + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row,COLUMN_FILEPATH),m_curFilesInfo.m_filePath); + + m_preView->cleanView(); + if(m_curFilesInfo.m_fileType == TYPE_FILE) + { + m_preView->creatView(m_curFilesInfo.m_marker);//刷新显示 + } + else if(m_curFilesInfo.m_fileType == TYPE_IMAGE) + { + m_preView->creatView(m_curFilesInfo.m_pixmap);//刷新显示 + } + + //将view的图片添加到列表中 + m_curFilesInfo.m_pic = m_preView->getPicture(m_curFilesInfo.m_marker); + m_curFilesInfo.m_creatBmpFlag = 1; + //将picture保存为多个宽度为2400像素的bmp + int num = m_curFilesInfo.m_pic.width() / PIXMAPWIDTH; + int lwidth = m_curFilesInfo.m_pic.width() % PIXMAPWIDTH; + if(lwidth != 0) + { + num +=1; + } + m_curFilesInfo.m_totalBlocks = num; + m_curFilesInfo.m_curPrintBlock = 0;//当前打印块数 + m_curFilesInfo.m_printedBlockNum = 0;//已打印块数 + m_curFilesInfo.m_leaveBlockNum = num;//剩余打印块数 + m_curFilesInfo.m_selectBlockNum = 0;//当前选择块数 + + m_curFilesInfo.m_printNum = number.toInt(); + m_curFilesInfo.m_startPoint = m_printViewWi->getStartPoint(); + m_curFilesInfo.m_printState = state; + + McPrintInfo McF; + McF.m_fileNums = row+1; + McF.m_fileTotalLength = (m_curFilesInfo.m_fileRect.right() - m_curFilesInfo.m_fileRect.left())/M_IDPMM; + McF.m_filesList.append(m_curFilesInfo); + m_curFileRow = row; + +#if(0) + //生成bmp块 + QDir printDir(m_printPath);//总的打印目录 + if(!printDir.exists()) + { + printDir.mkdir(m_printPath); + } + + QString mcFile = m_printPath + printDir.separator() + PRINTMCDIR + QString::number(m_curMcIdx+1); + QDir mcDir(mcFile);//对应每台机器打印目录 + if(!mcDir.exists()) + { + mcDir.mkdir(mcFile); + } + + QString filePath = mcFile + mcDir.separator() + PRINTFILEDIR + QString::number(row+1); + QDir fileDir(filePath);//对应每台机器的每个文件打印目录 + if(!fileDir.exists()) + { + fileDir.mkdir(filePath); + } + filePath = filePath + mcDir.separator(); + + m_creatBmpThread->setSavePath(filePath); + if(m_curFilesInfo.m_fileType == TYPE_FILE) + { + m_creatBmpThread->setPicture(m_preView->getPicture(m_curFilesInfo.m_marker,PENWIDTH)); + } + else if(m_curFilesInfo.m_fileType == TYPE_IMAGE) + { + m_creatBmpThread->setPicture(m_curFilesInfo.m_pixmap); + } + m_creatBmpThread->start(); +#endif + + ui->tableView_fileList->selectRow(row);//选中 + + if(g_machineList.size() <= 0) + { + return; + //g_machineList.append(McF); + } + else + { + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileNums = row+1; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileTotalLength += McF.m_fileTotalLength; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.append(m_curFilesInfo); + } + } + reflushMcFileInfo(); +} + +void MainWindow::slotFileListMenu(QPoint pos) +{ + QModelIndex index = ui->tableView_fileList->indexAt(pos); + int row = index.row(); + + if(row < 0){return;} + + QMenu* menu = new QMenu(this);//创建菜单 + QAction* action1 = new QAction(tr("Print preview"), this);//打印预览 + QAction* action2 = new QAction(tr("Number of modified print"), this);//修改打印份数 + QAction* action3 = new QAction(tr("Modify the starting print point"), this);//修改起始打印点 + QAction* action4 = new QAction(tr("View print information"), this);//查看打印信息 + QAction* action5 = new QAction(tr("Delete"), this);//删除 + + connect (action1,SIGNAL(triggered()),this,SLOT(slotPrintPreview())); + connect (action2,SIGNAL(triggered()),this,SLOT(slotPrintNumberSetDlgShow())); + connect (action3,SIGNAL(triggered()),this,SLOT(slotStartSetDlgShow())); + connect (action4,SIGNAL(triggered()),this,SLOT(slotViewPrintInfo())); + connect (action5,SIGNAL(triggered()),this,SLOT(slotDeleteFile())); + + menu->addAction(action1);//将action放入菜单中 + menu->addAction(action2);//将action放入菜单中 + menu->addAction(action3);//将action放入菜单中 + menu->addAction(action4);//将action放入菜单中 + menu->addAction(action5);//将action放入菜单中 + menu->popup(ui->tableView_fileList->viewport()->mapToGlobal(pos));//将菜单显示到鼠标所在位置 + + if(m_curFileRow != row) + { + m_curFileRow = row; + reflushPreview(row); + } + m_curFileRow = row; +} + +void MainWindow::slotMcListMenu(QPoint pos) +{ + QModelIndex index = ui->tableView_Connection->indexAt(pos); + int row = index.row(); + + if(row < 0){return;} + + QMenu* menu = new QMenu(this);//创建菜单 + QAction* action1 = new QAction(tr("Delete"), this);//删除 + connect (action1,SIGNAL(triggered()),this,SLOT(slotDeleteMc())); + + menu->addAction(action1);//将action放入菜单中 + menu->popup(ui->tableView_Connection->viewport()->mapToGlobal(pos));//将菜单显示到鼠标所在位置 + + if(m_curMcIdx != row) + { + refreshMcFileListShow(row); + ui->tableView_Connection->selectRow(m_curMcIdx); + m_curMcIdx = row; + } +} + +void MainWindow::slotPrintPreview() +{ + m_curFilesInfo = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow]; + m_printViewWi->refreshShow(m_curFilesInfo,0); +} + +void MainWindow::slotPrintNumberSetDlgShow() +{ + QString fileName = m_curFilesInfo.m_fileName; + QString printNumber= QString::number(m_curFilesInfo.m_printNum); + PrintNumberSetDialog numberSetDlg; + if(numberSetDlg.exec(fileName,printNumber) == 1) + { + int number = numberSetDlg.getPrintNumber(); + m_curFilesInfo.m_printNum = number; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow] = m_curFilesInfo; + m_tabelViewModelFile->item(m_curFileRow,COLUMN_NUMBERS)->setText(QString::number(number)); + } +} + +void MainWindow::slotStartSetDlgShow() +{ + QString fileName = m_curFilesInfo.m_fileName; + QString startPoint= QString::number(m_curFilesInfo.m_startPoint); + QString length= QString::number(m_curFilesInfo.m_fileRect.right()-m_curFilesInfo.m_fileRect.left()); + StartSetDialog startSetDlg; + if(startSetDlg.exec(fileName,startPoint,length) == 1) + { + int startPoint = startSetDlg.getStartPoint(); + m_curFilesInfo.m_startPoint = startPoint; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow] = m_curFilesInfo; + m_tabelViewModelFile->item(m_curFileRow,COLUMN_START)->setText(QString::number(startPoint)+"mm"); + } +} + +void MainWindow::slotViewPrintInfo() +{ + if(m_printInfoDlg != NULL) + { + m_printInfoDlg->setFilesInfo(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow]); + } +} + +void MainWindow::slotDeleteFile() +{ + if(m_curMcIdx < 0 || m_curMcIdx >= g_machineList.size()) + { + return; + } + + if(m_curFileRow < 0 || m_curFileRow >= g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size()) + { + return; + } + + if(QMessageBox::warning(this, + tr("Prompt"), + tr("Do you want to delete this drawing?"),//是否删除该项绘图? + QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok) + { + //判断是否正在打印,如果正在打印时不可删除 + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow].m_curPrintBlock != 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Printing this file, it cannot be deleted!"),//正在打印此文件,不可删除! + QMessageBox::Ok); + return; + } + + g_machineList[m_curMcIdx]->deleteFilePrintDat(m_curFileRow); + } +} + +void MainWindow::slotDeleteFileFinish() +{ + m_tabelViewModelFile->removeRow(m_curFileRow); + m_preView->cleanView(); + + reflushMcFileInfo(); + + if(m_curFileRow >= g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size()) + { + m_curFileRow -= 1; + } + ui->tableView_fileList->selectRow(m_curFileRow); + reflushPreview(m_curFileRow); +} + +void MainWindow::slotDeleteMc() +{ + if(QMessageBox::warning(this, + tr("Prompt"), + tr("After deletion, the machine cannot be controlled. Do you want to delete this machine?"),//删除后将不能控制机器,是否删除此机器? + QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok) + { + if(m_curMcIdx < 0 || m_curMcIdx >= g_machineList.size()) + { + return; + } + + //要删除的机器为正在加载文件的机器 + if(m_autoPrintLoadThread.isRunning() == true + && g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag != 1) + { + m_breakAutoLoadThread = 1; //暂停、取消线程的运行 + while(m_autoPrintLoadThread.isRunning() == true) + { + //等待线程停止 + } + } + //清除机器数据 + for(int i = 0; i < g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size(); i++) + { + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].clear(); + } + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.clear(); + g_machineList[m_curMcIdx]->m_mcPrintInfo.clear(); + + g_machineList.removeAt(m_curMcIdx);//从列表中删除 + m_tabelViewModelConn->removeRow(m_curMcIdx); + m_tabelViewModelFile->removeRows(0,m_tabelViewModelFile->rowCount()); + m_preView->cleanView(); + ui->tableView_Connection->clearSelection(); + ui->label_fileTotalVal->setText(""); + ui->label_fileTotalLenthVal->setText(""); + + //删除该机器的配置文件 + QDir apppath(qApp->applicationDirPath()); + QString configfile; + configfile = apppath.path() + apppath.separator() + "config.ini"; + QSettings settings(configfile, QSettings::IniFormat); + QString str = "MachineNo" + QString::number(m_curMcIdx+1); + settings.remove(str); + m_curMcIdx = -1; + QString iniFilePath = apppath.path() + apppath.separator() + str + ".ini"; + QFile::remove(iniFilePath); + } +} + +void MainWindow::onSendTimer() +{ + //总块数或者已生成块数为0时返回 + // if(m_totalPieces <= 0 || g_createdPieces <= 0 || m_sendPiece == m_totalPieces) + // { + // return; + // } + + // if(m_workState == START) + // { + // ui->actionStart->setEnabled(false); + // ui->actionStartIcon->setEnabled(false); + // } + // else + // { + // ui->actionStart->setEnabled(true); + // ui->actionStartIcon->setEnabled(true); + // } + + //已生成的比发送的块数多 + //if(g_createdPieces > m_sendPiece) + { + //发送文件 + // if(g_pMachine != NULL) + // { + // if(g_pDatList.size() > m_sendPiece) + // { + // g_pMachine->sendFileProc(m_sendPiece, g_pDatList[m_sendPiece]); + // m_sendPiece++; + // } + // } + } + + // if(m_sendPiece == m_totalPieces) + // { + // ui->actionStart->setEnabled(true); + // ui->actionStartIcon->setEnabled(true); + // } +} + +void MainWindow::slotLoadAutoPrintFiles() +{ + QString iniName = "MachineNo" + QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_mcNum) + ".ini"; + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + iniName; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + QString dirPath = setting.value("AutoPrintDir/fileDir").toString(); + QDir dir(dirPath); + if(!dir.exists()) + { + return; + } + + QString state = tr("Waitting"); + QString number = "1"; + QString start = "0mm"; + + QStringList filter; + filter << QString("*.plt") << QString("*.PLT") + << QString("*.png") << QString("*.PNG") + << QString("*.bmp") << QString("*.BMP") + << QString("*.jpg") << QString("*.JPG"); + QFileInfoList fileList = dir.entryInfoList(filter, QDir::Files | QDir::NoSymLinks); + + for(int i = 0; i < fileList.size(); i++) + { + if(m_breakAutoLoadThread == 1) + { + m_breakAutoLoadThread = 0; + return; + } + QCoreApplication::processEvents(QEventLoop::AllEvents); + + QFileInfo fileInfo(fileList[i]); + QString filePath = fileInfo.filePath(); + + int row = m_tabelViewModelFile->rowCount();//当前表格的行数 + m_tabelViewModelFile->insertRow(row);//在最后一行的后面插入一行 + + if(i < g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size()) + { + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].m_creatDataFlag == 1) + { + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_FILENAME),g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].m_fileName); + QRect rect = g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].m_fileRect; + QString length = QString::number((rect.right() - rect.left())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_LENGTH),length); + QString width = QString::number((rect.bottom() - rect.top())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_WIDTH),width); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_START),start); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_PRINTEDLENGTH),"0mm"); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_NUMBERS),number); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_STATE),state); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_FILEPATH),g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].m_filePath); + + continue; + } + } + + McFilesInfo curFilesInfo;//当前文件信息 + creatMarkerDat(curFilesInfo,filePath); + + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_FILENAME),curFilesInfo.m_fileName); + QRect rect = curFilesInfo.m_fileRect; + QString length = QString::number((rect.right() - rect.left())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_LENGTH),length); + QString width = QString::number((rect.bottom() - rect.top())/(int)M_IDPMM)+"mm"; + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_WIDTH),width); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_START),start); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_PRINTEDLENGTH),"0mm"); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_NUMBERS),number); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_STATE),state); + m_tabelViewModelFile->setData(m_tabelViewModelFile->index(row, COLUMN_FILEPATH),curFilesInfo.m_filePath); + + long long fileTotalLength = (curFilesInfo.m_fileRect.right() - curFilesInfo.m_fileRect.left())/M_IDPMM; + + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileNums = i+1; + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileTotalLength += fileTotalLength; + ui->label_fileTotalVal->setText(QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileNums)); + ui->label_fileTotalLenthVal->setText(QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileTotalLength)+"mm"); + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.append(curFilesInfo); + } + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag = 1; +} + +//1秒定时器 +void MainWindow::onOneSecondTimer() +{ + refConnectUi();//刷新连接 +} + +void MainWindow::creatMarkerDat(McFilesInfo &curFilesInfo, QString filePath) +{ + QFileInfo fileInfo(filePath); + curFilesInfo.m_marker.Initialize(); + + if(fileInfo.suffix().toUpper() == "PLT") + { + ImportHPGL importHPGL; + curFilesInfo.m_fileType = TYPE_FILE; + + //判断是否为加密文件 + if (importHPGL.IsSecretFile(filePath) == true) + { + // 文件路径 + QDir apppath(qApp->applicationDirPath()); + QString strSecretFile = apppath.path() + apppath.separator() + "Secret.plt"; + + importHPGL.BitMapDtat(filePath,strSecretFile); + importHPGL.IniPara(); + importHPGL.ReadSecretFile(strSecretFile,&curFilesInfo.m_marker); + } + else + { + importHPGL.IniPara(); + importHPGL.Read(filePath,&curFilesInfo.m_marker); + } + curFilesInfo.m_fileRect = curFilesInfo.m_marker.GetRect(); + } + else + { + curFilesInfo.m_fileType = TYPE_IMAGE; + QBitmap pixmap; + pixmap.load(filePath); + QRect rect; + rect.setRect(0,0,pixmap.width()/MMPIXELY*M_IDPMM,pixmap.height()/MMPIXELY*M_IDPMM); + + curFilesInfo.m_pixmap = pixmap; + curFilesInfo.m_fileRect = rect; + } + + curFilesInfo.m_filePath = filePath; + curFilesInfo.m_fileName = fileInfo.fileName(); + curFilesInfo.m_printNum = 1; + curFilesInfo.m_startPoint = 0; + curFilesInfo.m_printState = tr("Waitting"); + curFilesInfo.m_curPrintBlock = 0;//当前打印块数 + curFilesInfo.m_printedBlockNum = 0;//已打印块数 + curFilesInfo.m_selectBlockNum = 0;//当前选择块数 + curFilesInfo.m_creatDataFlag = 1; +} + +void MainWindow::on_actionDrawing_Setting_triggered() +{ + if(m_drawingSetDlg!= NULL) + { + m_drawingSetDlg->exec(); + } +} + +void MainWindow::on_actionPlotter_Setting_triggered() +{ + if(m_plotterSetDlg != NULL) + { + m_plotterSetDlg->exec(); + } +} + +void MainWindow::on_actionlog_triggered() +{ + if(m_historyDlg!= NULL) + { + m_historyDlg->exec(); + } +} + +void MainWindow::on_actionOpen_File_triggered() +{ + if(m_curMcIdx < 0 || m_curMcIdx >= g_machineList.size()) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Please select a machine!"), //请选择机器! + QMessageBox::Ok); + return; + } + + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag < 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Loading file, please wait!"), //正在加载文件,请等待! + QMessageBox::Ok); + return; + } + + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + "config.ini"; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + QString lastPath = setting.value("LastFilePath/filePath").toString(); //获取上次的打开路径 + + QString filePath; + + filePath = QFileDialog::getOpenFileName(this, + tr("Open File Dialog"),//打开文件对话框 + lastPath, + tr("File(*.plt *.dxf)"));//plt 文件 + + if (filePath.isNull() == 0) + { + QFileInfo fileInfo(filePath); + QString fileName = fileInfo.fileName(); + QString path = filePath; + setting.setValue("LastFilePath/filePath",path.remove(fileName)); //记录路径到QSetting中保存 + + m_curFilesInfo.m_marker.Initialize(); + + if(fileInfo.suffix().toUpper() == "DXF") + { + DxfHelper dxfHelper; + if(dxfHelper.generateDxf(filePath)) + { + dxfHelper.getDxfPaths(); // 获取转换出来的dxf所有类型图形的点集 + QImage img = dxfHelper.generateDXFImage(); // 获取预览图像 + img.save("D:\\1.png"); + } + } + if(fileInfo.suffix().toUpper() == "PLT") + { + ImportHPGL importHPGL; + //判断是否为加密文件 + if (importHPGL.IsSecretFile(filePath) == true) + { + // 文件路径 + QDir apppath(qApp->applicationDirPath()); + QString strSecretFile = apppath.path() + apppath.separator() + "Secret.plt"; + + importHPGL.BitMapDtat(filePath,strSecretFile); + importHPGL.IniPara(); + importHPGL.ReadSecretFile(strSecretFile,&m_curFilesInfo.m_marker); + } + else + { + importHPGL.IniPara(); + importHPGL.Read(filePath,&m_curFilesInfo.m_marker); + } + //importHPGL.creatPolylinePainterPath(); + + QFileInfo file(filePath); + m_curFilesInfo.m_filePath = filePath; + m_curFilesInfo.m_fileName = file.fileName(); + m_curFilesInfo.m_fileType = TYPE_FILE; + m_curFilesInfo.m_fileRect = m_curFilesInfo.m_marker.GetRect(); + //m_curFilesInfo.m_painterPath = importHPGL.GetPolylinePainterPath(); + + m_printViewWi->refreshShow(m_curFilesInfo,1); + } + } + return; +} + +void MainWindow::on_tableView_fileList_clicked(const QModelIndex &index) +{ + int row = index.row(); + m_curFileRow = row; + reflushPreview(row); + + //判断是否正在打印,如果正在打印时不可删除、移动、修改打印信息 + ui->frame_fileBtn->setEnabled(true); + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[m_curFileRow].m_curPrintBlock != 0) + { + ui->frame_fileBtn->setEnabled(false); + } + + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_mcWorkState == Busying) + { + if((m_curFileRow+1) == m_curPrintFileIdx) + { + ui->pushButton_up->setEnabled(false); + } + } +} + +void MainWindow::on_pushButton_up_clicked() +{ + changeRowData(-1); +} + +void MainWindow::on_pushButton_down_clicked() +{ + changeRowData(1); +} + +void MainWindow::on_pushButton_delete_clicked() +{ + slotDeleteFile(); +} + +void MainWindow::on_pushButton_preview_clicked() +{ + slotPrintPreview(); +} + +void MainWindow::on_actionOpenFileIcon_triggered() +{ + on_actionOpen_File_triggered(); +} + +void MainWindow::on_actionOpen_Image_triggered() +{ + if(m_curMcIdx < 0 || m_curMcIdx >= g_machineList.size()) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Please select a machine!"), //请选择机器! + QMessageBox::Ok); + return; + } + + if(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag < 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Loading file, please wait!"), //正在加载文件,请等待! + QMessageBox::Ok); + return; + } + + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + "config.ini"; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + QString lastPath = setting.value("LastFilePath/filePath").toString(); //获取上次的打开路径 + + QString filePath; + + filePath = QFileDialog::getOpenFileName(this, + tr("Open File Dialog"),//打开文件对话框 + lastPath, + tr("Image File(*.png *.bmp *.jpg)"));//图像文件 + + if (filePath.isNull() == 0) + { + QFileInfo fileInfo(filePath); + QString fileName = fileInfo.fileName(); + QString path = filePath; + setting.setValue("LastFilePath/filePath",path.remove(fileName)); //记录路径到QSetting中保存 + + m_curFilesInfo.m_marker.Initialize(); + m_curFilesInfo.m_filePath = filePath; + m_curFilesInfo.m_fileName = fileName; + m_curFilesInfo.m_fileType = TYPE_IMAGE; + + QBitmap pixmap; + pixmap.load(filePath); + QRect rect; + rect.setRect(0,0,pixmap.width()/MMPIXELY*M_IDPMM,pixmap.height()/MMPIXELY*M_IDPMM); + + m_curFilesInfo.m_pixmap = pixmap; + m_curFilesInfo.m_fileRect = rect; + m_printViewWi->refreshShow(m_curFilesInfo,1); + } +} + +void MainWindow::on_actionOpenImageIcon_triggered() +{ + on_actionOpen_Image_triggered(); +} + +void MainWindow::on_actionDelete_triggered() +{ + slotDeleteFile(); +} + +void MainWindow::on_actionAuto_Print_Dir_triggered() +{ + if(m_curMcIdx < 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Please select the machine you want to set the directory!"),//请选择要设置目录的机器! + QMessageBox::Ok); + return; + } + + //以机器编号命名ini文件 + QString iniName = "MachineNo" + QString::number(g_machineList[m_curMcIdx]->m_mcPrintInfo.m_mcNum) + ".ini"; + QDir apppath(qApp->applicationDirPath()); + QString iniPath = apppath.path() + apppath.separator() + iniName; + QSettings setting(iniPath, QSettings::IniFormat); //QSettings能记录一些程序中的信息,下次再打开时可以读取出来 + + // 获取文件路径 + QString fileDir = QFileDialog::getExistingDirectory(this, tr("Select Folder")); + if (!fileDir.isEmpty()) + { + setting.setValue("AutoPrintDir/fileDir",fileDir); //记录路径到QSetting中保存 + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_loadFileFinishFlag = -1; + for(int i = 0; i < g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.size(); i++) + { + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList[i].clear(); + } + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_filesList.clear(); + g_machineList[m_curMcIdx]->m_mcPrintInfo.m_fileTotalLength = 0; + refreshMcFileListShow(m_curMcIdx); + } +} + +void MainWindow::on_actionStart_triggered() +{ + m_workState = START; + startCreatBmpAndSend(m_curMcIdx); +} + +void MainWindow::on_actionStartIcon_triggered() +{ + m_workState = START; + startCreatBmpAndSend(m_curMcIdx); +} + +void MainWindow::on_actionPause_triggered() +{ + m_workState = PAUSE; +} + +void MainWindow::on_actionPauseIcon_triggered() +{ + m_workState = PAUSE; +} + +void MainWindow::on_actionAddMachine_triggered() +{ + AddMachineDialog addMcDlg; + if(addMcDlg.exec() == 1) + { + //读取配置文件是否存在同名的机器名称 + QDir apppath(qApp->applicationDirPath()); + QString configfile; + configfile = apppath.path() + apppath.separator() + "config.ini"; + QSettings settings(configfile, QSettings::IniFormat); + QString mcName = addMcDlg.getMcName(); + QString serverIp = addMcDlg.getMcIp(); + quint16 serverPort = 5000; + + int idx = 0; + for(int i = 1; i <= MACHINE_NUM; i++) + { + QString str = "MachineNo" + QString::number(i); + QString keyStr = str + + "/name"; + bool bl = settings.contains(keyStr); + if(bl == false) + { + QString strName = str + "/name"; + settings.setValue(strName,mcName); + QString strIp = str + "/ip"; + settings.setValue(strIp,serverIp); + QString strPort = str + "/port"; + settings.setValue(strPort,serverPort); + idx = i; + break; + } + } + + if(idx == 0) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("The maximum number of connections has been reached and cannot be added again!"),//已达到最大连接数量,不可再添加! + QMessageBox::Ok); + return; + } + + //本地IP和端口 + QString localIp = settings.value("Local/ip").toString(); + quint16 localPort = settings.value("Local/port").toInt(); + + Machine *pMachine = new Machine(); //建立连接 + pMachine->setIpAndPort(mcName,serverIp,serverPort,localIp,localPort);//设置IP和端口 + pMachine->startCommunication(); + McPrintInfo mcf; + mcf.m_mcNum = idx; + mcf.m_mcName = mcName; + mcf.m_ip = serverIp; + mcf.m_port = serverPort; + mcf.m_loadFileFinishFlag = 1; + pMachine->m_mcPrintInfo = mcf; + g_machineList.append(pMachine); + + int row = m_tabelViewModelConn->rowCount();//当前表格的行数 + m_tabelViewModelConn->insertRow(row);//在最后一行的后面插入一行 + refreshMcFileListShow(row); + ui->tableView_Connection->selectRow(row); + refreshOneMcShow(row,g_machineList.size()-1); + if(!ui->menuFile_F->isEnabled()) + { + if(g_machineList.size() > 0) + { + ui->menuFile_F->setEnabled(true); + } + } + } +} + +void MainWindow::on_actionDeletMachine_triggered() +{ + slotDeleteMc(); +} + +void MainWindow::on_tableView_Connection_clicked(const QModelIndex &index) +{ + refreshMcFileListShow(index.row()); + ui->tableView_Connection->selectRow(m_curMcIdx); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..bd83a2f --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,157 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drawingsetdialog.h" +#include "plottersetdialog.h" +#include "historydialog.h" +#include "printviewwindow.h" +#include "printnumbersetdialog.h" +#include "startsetdialog.h" +#include "printinfodialog.h" +#include "addmachinedialog.h" +#include "datafile/hpgl/importhpgl.h" +#include "datafile/dxf/dxfhelper.h" +#include "machine/bmp/creatprintbmp.h" + +//文件列表 +#define COLUMN_NUM 8 //列数 +#define COLUMN_COLWIDTH 96 //列宽 +#define COLUMN_FILENAME 0 //第1列-文件名称 +#define COLUMN_LENGTH 1 //第2列-文件长度 +#define COLUMN_WIDTH 2 //第3列-文件宽度 +#define COLUMN_START 3 //第4列-文件起始打印点 +#define COLUMN_PRINTEDLENGTH 4 //第5列-文件已打印长度 +#define COLUMN_NUMBERS 5 //第6列-文件打印数量 +#define COLUMN_STATE 6 //第7列-文件打印状态 +#define COLUMN_FILEPATH 7 //第8列-文件路径 + +//机器连接列表 +#define CONN_COLUMN_NUM 5 //列数 +#define CONN_COLUMN_COLWIDTH 100 //列宽 +#define CONN_COLUMN_MCNAME 0 //第1列-机器名称 +#define CONN_COLUMN_MCIP 1 //第2列-机器IP +#define CONN_COLUMN_MCCONSTATE 2 //第3列-机器连接状态 +#define CONN_COLUMN_MCWORKSTATE 3 //第4列-机器工作状态 +#define CONN_COLUMN_MCPROGRESS 4 //第5列-机器文件发送进度 + +#define AUTOPRINT 1 +#define NOAUTOPRINT 0 + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + DrawingSetDialog *m_drawingSetDlg; + PlotterSetDialog *m_plotterSetDlg; + HistoryDialog *m_historyDlg; + PrintViewWindow *m_printViewWi; + PrintInfoDialog *m_printInfoDlg; + MyGraphicsView *m_preView; + QTimer *m_sendTimer; + QTimer * m_pTimer;//建立连接的定时器 + + int m_curMcIdx;//列表所选机器索引 + McFilesInfo m_curFilesInfo;//当前文件信息 + QStandardItemModel *m_tabelViewModelFile; + QStandardItemModel *m_tabelViewModelConn; + int m_curFileRow;//当前选中文件索引 + int m_curPrintFileIdx;//当前打印的文件索引 + int m_curBlockRow;//数据块 + QString m_printPath; + int m_sortType;//排序类型 + + int m_workState;//工作状态(开始、停止) + int m_printMode;//打印模式(自动、非自动) + + int m_breakAutoLoadThread;//打断自动加载文件线程 + QFuture m_autoPrintLoadThread;//自动绘图目录加载线程 + +private: + void closeEvent(QCloseEvent *e); + void reflushPreview(int row); + void reflushMcFileInfo(); + void changeRowData(int move); + bool deleteDir(QString path); + void setButtonEnable(bool bl); + void startCreatBmpAndSend(int mcIdx = -1);//开始创建位图并发送 + QPicture creatFilePicture(McFilesInfo & mcFileInfo, s16 penWidth = 1); + //刷新连接状态 + void refConnectUi();//刷新连接状态(1秒) + void refConnectUi(Machine * pMachine,int & linkSta, int idx); + void refreshMcListShow();//刷新机器列表显示 + void refreshOneMcShow(int row,int idx);//刷新单个机器信息显示 + int refreshMcFileListShow(int idx); + void creatMarkerDat(McFilesInfo &curFilesInfo, QString filePath);//创建Marker数据 + +public: + void initAllWinForm(); + void iniViewModel(); + void loadAutoPrintDirFiles();//加载自动绘图目录的文件 + +private slots: + void slotAddNewFileToList(int newFlag); + void slotFileListMenu(QPoint pos); + void slotMcListMenu(QPoint pos); + void slotPrintPreview(); + void slotPrintNumberSetDlgShow(); + void slotStartSetDlgShow(); + void slotViewPrintInfo(); + void slotDeleteFile();//删除文件 + void slotDeleteFileFinish();//删除文件完成并刷新 + void slotDeleteMc();//删除机器 + void onSendTimer(void); + void slotLoadAutoPrintFiles(); + void onOneSecondTimer();//1秒定时器 + +private slots: + void on_actionDrawing_Setting_triggered(); + void on_actionPlotter_Setting_triggered(); + void on_actionlog_triggered(); + void on_actionOpen_File_triggered(); + void on_tableView_fileList_clicked(const QModelIndex &index); + void on_pushButton_up_clicked(); + void on_pushButton_down_clicked(); + void on_pushButton_delete_clicked(); + void on_pushButton_preview_clicked(); + void on_actionOpenFileIcon_triggered(); + void on_actionOpen_Image_triggered(); + void on_actionOpenImageIcon_triggered(); + void on_actionDelete_triggered(); + void on_actionAuto_Print_Dir_triggered(); + void on_actionStart_triggered(); + void on_actionStartIcon_triggered(); + void on_actionPause_triggered(); + void on_actionPauseIcon_triggered(); + void on_actionAddMachine_triggered(); + void on_actionDeletMachine_triggered(); + void on_tableView_Connection_clicked(const QModelIndex &index); +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..776ed09 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,514 @@ + + + MainWindow + + + + 0 + 0 + 1024 + 600 + + + + + 1024 + 600 + + + + MainWindow + + + + + + + 6 + + + + + + + Qt::NoFocus + + + QTableView::item::selected +{ + background:rgb(205,232,255); +} + + + + + + + + + + + 0 + + + + + Print Info + + + + + 10 + 20 + 101 + 20 + + + + Total Files: + + + + + + 112 + 20 + 81 + 20 + + + + + + + + + + 362 + 20 + 121 + 20 + + + + + + + + + + 250 + 20 + 111 + 20 + + + + Total Length: + + + + + + 10 + 44 + 81 + 20 + + + + Progress: + + + + + + 100 + 46 + 241 + 16 + + + + 0 + + + + + + + + + + + + + 16777215 + 26 + + + + Qt::LeftToRight + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 0 + 0 + 25 + 25 + + + + border-image: url(:/resources/up.bmp); + + + + + + + 24 + 24 + + + + + + + 30 + 0 + 25 + 25 + + + + border-image: url(:/resources/down.bmp); + + + + + + + + + 60 + 0 + 25 + 25 + + + + border-image: url(:/resources/delete.bmp); + + + + + + + + + 90 + 0 + 25 + 25 + + + + border-image: url(:/resources/edit.bmp); + + + + + + + + + + + Qt::NoFocus + + + QTableView::item::selected +{ + background:rgb(205,232,255); +} + + + + + + + + + + + + + + + + + + + 0 + 0 + 1024 + 23 + + + + + File(F) + + + + Testing + + + + + + + + + + + + + + + + Connect Manage(C) + + + + + + + Setting(S) + + + + + + + Language(L) + + + + + + + About(A) + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + + + Open File + + + Ctrl+O + + + + + Open Image + + + Ctrl+I + + + + + Start + + + + + Pause + + + + + Delete + + + Ctrl+Del + + + + + Exit + + + + + USB + + + + + NetWork + + + + + Delete Link + + + + + Auto Print Dir + + + + + log + + + + + Parameter Import + + + + + Parameter Export + + + + + Drawing Setting + + + + + Plotter Setting View + + + + + Chinese + + + + + English + + + + + + :/resources/OpenFile.bmp:/resources/OpenFile.bmp + + + OpenFileIcon + + + OpenFile + + + Ctrl+O + + + + + + :/resources/OpenImage.png:/resources/OpenImage.png + + + OpenImageIcon + + + OpenImage + + + Ctrl+I + + + + + + :/resources/start.bmp:/resources/start.bmp + + + StartIcon + + + Start + + + + + + :/resources/pause.bmp:/resources/pause.bmp + + + PauseIcon + + + Pause + + + + + + :/resources/SetPara.bmp:/resources/SetPara.bmp + + + DrawingSetIcon + + + DrawingSetting + + + + + Add Machine + + + + + Delete Machine + + + + + test1.plt + + + + + + + + diff --git a/plottersetdialog.cpp b/plottersetdialog.cpp new file mode 100644 index 0000000..9a98a1e --- /dev/null +++ b/plottersetdialog.cpp @@ -0,0 +1,16 @@ +#include "plottersetdialog.h" +#include "ui_plottersetdialog.h" + +PlotterSetDialog::PlotterSetDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PlotterSetDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); +} + +PlotterSetDialog::~PlotterSetDialog() +{ + delete ui; +} diff --git a/plottersetdialog.h b/plottersetdialog.h new file mode 100644 index 0000000..eff9e13 --- /dev/null +++ b/plottersetdialog.h @@ -0,0 +1,22 @@ +#ifndef PLOTTERSETDIALOG_H +#define PLOTTERSETDIALOG_H + +#include + +namespace Ui { +class PlotterSetDialog; +} + +class PlotterSetDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PlotterSetDialog(QWidget *parent = 0); + ~PlotterSetDialog(); + +private: + Ui::PlotterSetDialog *ui; +}; + +#endif // PLOTTERSETDIALOG_H diff --git a/plottersetdialog.ui b/plottersetdialog.ui new file mode 100644 index 0000000..0bcb0aa --- /dev/null +++ b/plottersetdialog.ui @@ -0,0 +1,798 @@ + + + PlotterSetDialog + + + + 0 + 0 + 1129 + 394 + + + + Dialog + + + + + 20 + 10 + 551 + 51 + + + + Print startup mode selection + + + + + 20 + 22 + 241 + 16 + + + + Auto Print + + + + + + + 20 + 70 + 551 + 51 + + + + Print mode selection + + + + + 20 + 22 + 89 + 16 + + + + Single + + + + + + 200 + 22 + 89 + 16 + + + + Double + + + + + + + 20 + 190 + 551 + 91 + + + + Graphic error correction + + + + + 240 + 26 + 61 + 20 + + + + 1000 + + + + + + 310 + 30 + 30 + 12 + + + + mm + + + + + + 53 + 26 + 181 + 20 + + + + 1 meter actual output: + + + + + + 310 + 60 + 30 + 12 + + + + mm + + + + + + 53 + 56 + 181 + 20 + + + + 1 meter actual output: + + + + + + 240 + 56 + 61 + 20 + + + + 1000 + + + + + + 340 + 38 + 201 + 26 + + + + Drawing 1 meter Square + + + + + + 6 + 26 + 42 + 20 + + + + background-image: url(:/resources/page_cy.bmp); + + + + + + + + + 6 + 55 + 42 + 20 + + + + background-image: url(:/resources/page_cx.bmp); + + + + + + + + + + 590 + 10 + 521 + 81 + + + + Two way print error setting + + + + + 198 + 24 + 61 + 20 + + + + 0 + + + + + + 268 + 26 + 30 + 12 + + + + mm + + + + + + 23 + 24 + 168 + 20 + + + + Two way print error: + + + + + + 268 + 56 + 30 + 12 + + + + mm + + + + + + 23 + 52 + 168 + 20 + + + + Print drawing width: + + + + + + 198 + 52 + 61 + 20 + + + + 1600 + + + + + + 300 + 34 + 211 + 26 + + + + Print Error Correction + + + + + + + 590 + 100 + 521 + 252 + + + + Error setting between nozzles + + + + + 10 + 21 + 501 + 94 + + + + + + + + + 240 + 8 + 61 + 20 + + + + 0 + + + + + + 310 + 8 + 51 + 20 + + + + pixel + + + + + + 13 + 8 + 221 + 20 + + + + 1、2 error between nozzles: + + + + + + 310 + 36 + 51 + 20 + + + + pixel + + + + + + 13 + 36 + 221 + 20 + + + + 2、3 error between nozzles: + + + + + + 240 + 36 + 61 + 20 + + + + 0 + + + + + + 13 + 64 + 221 + 20 + + + + 3、4 error between nozzles: + + + + + + 240 + 64 + 61 + 20 + + + + 0 + + + + + + 310 + 64 + 51 + 20 + + + + pixel + + + + + + 390 + 23 + 65 + 48 + + + + background-image: url(:/resources/ErrorY.bmp); + + + + + + + + + + 10 + 122 + 501 + 94 + + + + + + + + + 240 + 8 + 61 + 20 + + + + 0 + + + + + + 310 + 8 + 51 + 20 + + + + pixel + + + + + + 13 + 8 + 221 + 20 + + + + 1、2 overlap between nozzles: + + + + + + 310 + 36 + 51 + 20 + + + + pixel + + + + + + 13 + 36 + 221 + 20 + + + + 2、3 overlap between nozzles: + + + + + + 240 + 36 + 61 + 20 + + + + 0 + + + + + + 13 + 64 + 221 + 20 + + + + 3、4 overlap between nozzles: + + + + + + 240 + 64 + 61 + 20 + + + + 0 + + + + + + 310 + 64 + 51 + 20 + + + + pixel + + + + + + 390 + 23 + 65 + 48 + + + + background-image: url(:/resources/ErrorX.bmp); + + + + + + + + + + 190 + 220 + 321 + 26 + + + + Correction diagram between nozzles + + + + + + + 20 + 290 + 551 + 62 + + + + Paper feeding error correction + + + + + 240 + 26 + 61 + 20 + + + + 0 + + + + + + 310 + 30 + 30 + 12 + + + + mm + + + + + + 36 + 26 + 201 + 20 + + + + Paper feeding error set: + + + + + + 340 + 22 + 201 + 26 + + + + Print paper feed error + + + + + + + 980 + 360 + 60 + 26 + + + + Ok + + + + + + 1050 + 360 + 60 + 26 + + + + Cancel + + + + + + 20 + 130 + 551 + 51 + + + + Sprinkler selection + + + + + 20 + 22 + 91 + 16 + + + + Nozzle 1 + + + + + + 130 + 22 + 91 + 16 + + + + Nozzle 2 + + + + + + 240 + 22 + 91 + 16 + + + + Nozzle 3 + + + + + + 350 + 22 + 91 + 16 + + + + Nozzle 4 + + + + + + + diff --git a/printinfodialog.cpp b/printinfodialog.cpp new file mode 100644 index 0000000..12dcb20 --- /dev/null +++ b/printinfodialog.cpp @@ -0,0 +1,119 @@ +#include "printinfodialog.h" +#include "ui_printinfodialog.h" + +PrintInfoDialog::PrintInfoDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PrintInfoDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + + //QListView + ui->listView_blockList->setDragEnabled(false); //控件不允许拖动 + m_listViewModel = new QStringListModel(ui->listView_blockList); + ui->listView_blockList->setModel(m_listViewModel); + + m_curBlockRow = -1; + m_preView = new MyGraphicsView(); + ui->horizontalLayout->addWidget(m_preView); +} + +PrintInfoDialog::~PrintInfoDialog() +{ + delete ui; +} + +void PrintInfoDialog::on_listView_blockList_clicked(const QModelIndex &index) +{ + QString str = "0 - "; + int row = index.row(); + QString str1; + if(m_curBlockRow != row) + { + int x = row * PIXMAPWIDTH; + QPoint p; + p.setX(x); + p.setY(0); + m_preView->reflushBlockView(p); + m_curBlockRow = row; + m_curFilesInfo.m_selectBlockNum = row+1; + str = QString::number((m_curFilesInfo.m_selectBlockNum-1)*BLOCK_MM)+" - "; + if(row == m_listViewModel->rowCount() - 1) + { + str1 = QString::number((m_curFilesInfo.m_fileRect.right() - m_curFilesInfo.m_fileRect.left())/(int)M_IDPMM); + } + else + { + str1 = QString::number(m_curFilesInfo.m_selectBlockNum*BLOCK_MM); + } + } + else + { + QPoint p; + p.setX(-1); + p.setY(-1); + m_preView->reflushBlockView(p); + ui->listView_blockList->clearSelection(); + m_curBlockRow = -1; + m_curFilesInfo.m_selectBlockNum = 0; + str1 = QString::number(m_curFilesInfo.m_selectBlockNum*BLOCK_MM); + } + ui->label_selectBlockNumVal->setText(QString::number(m_curFilesInfo.m_selectBlockNum)+"("+str+str1+"mm)"); +} + +void PrintInfoDialog::reflushFileInfo() +{ + //刷新块数列表和文件信息 + QStringList strList; + strList.clear(); + int totalBlocks = m_curFilesInfo.m_totalBlocks; + for(int i = 1; i <= totalBlocks; i++) + { + QString str = QString::number(i) + " " + tr("piece");//块 + strList.append(str); + } + m_listViewModel->setStringList(strList); + + ui->label_fileNameVal->setText(m_curFilesInfo.m_fileName); + + int length = (m_curFilesInfo.m_fileRect.right() - m_curFilesInfo.m_fileRect.left())/M_IDPMM; + int height = (m_curFilesInfo.m_fileRect.bottom() - m_curFilesInfo.m_fileRect.top())/M_IDPMM; + QString WH = QString::number(length) + "x" + QString::number(height)+ "mm"; + ui->label_drawWHVal->setText(WH); + + ui->label_printNumVal->setText(QString::number(m_curFilesInfo.m_printNum)); + ui->label_startPointVal->setText(QString::number(m_curFilesInfo.m_startPoint)+"mm"); + + ui->label_fileBlockNumVal->setText(QString::number(m_curFilesInfo.m_totalBlocks)); + ui->label_currentBlockVal->setText(QString::number(m_curFilesInfo.m_curPrintBlock)+"("+QString::number(m_curFilesInfo.m_curPrintBlock*BLOCK_MM)+"mm)"); + ui->label_printedBlockNumVal->setText(QString::number(m_curFilesInfo.m_printedBlockNum)+"("+QString::number(m_curFilesInfo.m_printedBlockNum*BLOCK_MM)+"mm)"); + + int leaveLength = length - m_curFilesInfo.m_printedBlockNum*BLOCK_MM; + ui->label_leaveBlockNumVal->setText(QString::number(m_curFilesInfo.m_leaveBlockNum)+"("+QString::number(leaveLength)+"mm)"); + ui->label_selectBlockNumVal->setText(QString::number(m_curFilesInfo.m_selectBlockNum)+"("+"0 - "+QString::number(m_curFilesInfo.m_selectBlockNum*BLOCK_MM)+"mm)"); +} + +void PrintInfoDialog::setFilesInfo(McFilesInfo info) +{ + m_curFilesInfo = info; + + m_preView->cleanView(); + if(m_curFilesInfo.m_fileType == TYPE_FILE) + { + m_preView->creatView(m_curFilesInfo.m_marker);//刷新显示 + } + else if(m_curFilesInfo.m_fileType == TYPE_IMAGE) + { + m_preView->creatView(m_curFilesInfo.m_pixmap);//刷新显示 + } + + reflushFileInfo(); + + QDialog::exec(); +} + +void PrintInfoDialog::on_pushButton_back_clicked() +{ + done(0); +} diff --git a/printinfodialog.h b/printinfodialog.h new file mode 100644 index 0000000..4e12b72 --- /dev/null +++ b/printinfodialog.h @@ -0,0 +1,40 @@ +#ifndef PRINTINFODIALOG_H +#define PRINTINFODIALOG_H + +#include +#include +#include "main.h" +#include "datafile/view/mygraphicsview.h" +#include "machine/machine.h" + +namespace Ui { +class PrintInfoDialog; +} + +class PrintInfoDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PrintInfoDialog(QWidget *parent = 0); + ~PrintInfoDialog(); + +private slots: + void on_listView_blockList_clicked(const QModelIndex &index); + void on_pushButton_back_clicked(); + +private: + Ui::PrintInfoDialog *ui; + QStringListModel *m_listViewModel; + int m_curBlockRow;//数据块 + MyGraphicsView *m_preView; + McFilesInfo m_curFilesInfo;//当前文件信息 + +private: + void reflushFileInfo(); + +public: + void setFilesInfo(McFilesInfo filesInfo); +}; + +#endif // PRINTINFODIALOG_H diff --git a/printinfodialog.ui b/printinfodialog.ui new file mode 100644 index 0000000..acf7b7b --- /dev/null +++ b/printinfodialog.ui @@ -0,0 +1,309 @@ + + + PrintInfoDialog + + + + 0 + 0 + 919 + 490 + + + + Dialog + + + + + 620 + 10 + 291 + 221 + + + + Qt::ClickFocus + + + + + + 620 + 240 + 291 + 211 + + + + + 16777215 + 16777215 + + + + Working Info + + + + + 10 + 20 + 91 + 20 + + + + File Name: + + + + + + 102 + 20 + 131 + 20 + + + + + + + + + + 122 + 40 + 120 + 20 + + + + + + + + + + 10 + 40 + 111 + 20 + + + + Width/Height: + + + + + + 122 + 60 + 121 + 20 + + + + + + + + + + 10 + 60 + 111 + 20 + + + + Print Number: + + + + + + 162 + 80 + 90 + 20 + + + + + + + + + + 10 + 80 + 151 + 20 + + + + Start Print Point: + + + + + + 122 + 100 + 121 + 20 + + + + + + + + + + 10 + 100 + 111 + 20 + + + + Total Blocks: + + + + + + 182 + 120 + 80 + 20 + + + + + + + + + + 10 + 120 + 171 + 20 + + + + Current Print Block: + + + + + + 192 + 140 + 71 + 20 + + + + + + + + + + 10 + 140 + 171 + 20 + + + + Printed Block Number: + + + + + + 172 + 160 + 86 + 20 + + + + + + + + + + 10 + 160 + 161 + 20 + + + + Leave Block Number: + + + + + + 10 + 180 + 171 + 20 + + + + Select Block Number: + + + + + + 182 + 180 + 80 + 20 + + + + + + + + + + + 834 + 460 + 75 + 23 + + + + Back + + + + + + 9 + 9 + 601 + 441 + + + + + + + + diff --git a/printnumbersetdialog.cpp b/printnumbersetdialog.cpp new file mode 100644 index 0000000..05712f1 --- /dev/null +++ b/printnumbersetdialog.cpp @@ -0,0 +1,47 @@ +#include "printnumbersetdialog.h" +#include "ui_printnumbersetdialog.h" + +PrintNumberSetDialog::PrintNumberSetDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::PrintNumberSetDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + m_printNumber = 0; + //整数 + QIntValidator *Validator = new QIntValidator(this); + ui->lineEdit_number->setValidator(Validator); +} + +PrintNumberSetDialog::~PrintNumberSetDialog() +{ + delete ui; +} + +int PrintNumberSetDialog::exec(QString title,QString text) +{ + ui->lineEdit_number->setText(text); + m_printNumber = text.toInt(); + this->setWindowTitle(title); + return QDialog::exec(); +} + +void PrintNumberSetDialog::on_pushButton_ok_clicked() +{ + m_printNumber = ui->lineEdit_number->text().toInt(); + if(m_printNumber <= 0 || m_printNumber > 255) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Unreasonable value input!"),//数值输入不合理 + QMessageBox::Ok); + return; + } + done(1); +} + +void PrintNumberSetDialog::on_pushButton_cancel_clicked() +{ + done(0); +} diff --git a/printnumbersetdialog.h b/printnumbersetdialog.h new file mode 100644 index 0000000..342e4d6 --- /dev/null +++ b/printnumbersetdialog.h @@ -0,0 +1,30 @@ +#ifndef PRINTNUMBERSETDIALOG_H +#define PRINTNUMBERSETDIALOG_H + +#include +#include + +namespace Ui { +class PrintNumberSetDialog; +} + +class PrintNumberSetDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PrintNumberSetDialog(QWidget *parent = 0); + ~PrintNumberSetDialog(); + int exec(QString title,QString text); + inline int getPrintNumber(){return m_printNumber;} + +private slots: + void on_pushButton_ok_clicked(); + void on_pushButton_cancel_clicked(); + +private: + Ui::PrintNumberSetDialog *ui; + int m_printNumber; +}; + +#endif // PRINTNUMBERSETDIALOG_H diff --git a/printnumbersetdialog.ui b/printnumbersetdialog.ui new file mode 100644 index 0000000..7563ebc --- /dev/null +++ b/printnumbersetdialog.ui @@ -0,0 +1,84 @@ + + + PrintNumberSetDialog + + + + 0 + 0 + 255 + 107 + + + + Dialog + + + + + 180 + 32 + 54 + 16 + + + + (1-255) + + + + + + 90 + 30 + 81 + 20 + + + + 1 + + + + + + 20 + 30 + 61 + 16 + + + + Number: + + + + + + 110 + 70 + 60 + 26 + + + + Ok + + + + + + 180 + 70 + 60 + 26 + + + + Cancel + + + + + + diff --git a/printviewwindow.cpp b/printviewwindow.cpp new file mode 100644 index 0000000..e1bb3df --- /dev/null +++ b/printviewwindow.cpp @@ -0,0 +1,109 @@ +#include "printviewwindow.h" +#include "ui_printviewwindow.h" + +PrintViewWindow::PrintViewWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::PrintViewWindow) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + m_startPoint = 0; + m_printNumber = 0; + m_filePath.clear(); + m_addNewFileFlag = 0; + m_view = NULL; + + //整数 + QIntValidator *Validator = new QIntValidator(this); + ui->lineEdit_start->setValidator(Validator); + ui->lineEdit_number->setValidator(Validator); + + m_view = new MyGraphicsView(); + connect(m_view,SIGNAL(siMouseMove(QPointF)),this,SLOT(slotShowPoint(QPointF))); +} + +PrintViewWindow::~PrintViewWindow() +{ + if(m_view != NULL) + { + delete m_view; + m_view = NULL; + } + delete ui; +} + +void PrintViewWindow::refreshShow(McFilesInfo mcFilesInfo,int flag) +{ + m_startPoint = 0; + m_printNumber = 1; + m_addNewFileFlag = flag; + if(flag == 1) + { + ui->lineEdit_number->setText("1"); + ui->lineEdit_start->setText("0"); + } + else + { + ui->lineEdit_number->setText(QString::number(mcFilesInfo.m_printNum)); + ui->lineEdit_start->setText(QString::number(mcFilesInfo.m_startPoint)); + } + + m_filePath = mcFilesInfo.m_filePath; + m_length = (mcFilesInfo.m_fileRect.right() - mcFilesInfo.m_fileRect.left())/M_IDPMM; + int width = (mcFilesInfo.m_fileRect.bottom() - mcFilesInfo.m_fileRect.top())/M_IDPMM; + this->setWindowTitle(m_filePath+"("+QString::number(m_length)+"mm"+" * " + QString::number(width) + "mm)"); + + m_view->cleanView(); + if(mcFilesInfo.m_fileType == TYPE_FILE) + { + m_view->creatView(mcFilesInfo.m_marker); + } + else if(mcFilesInfo.m_fileType == TYPE_IMAGE) + { + m_view->creatView(mcFilesInfo.m_pixmap); + } + + //如果是最大化变为正常大小 + if(this->windowState() == Qt::WindowMaximized) + { + this->setWindowState(Qt::WindowMinimized); + this->showNormal(); + } + + ui->horizontalLayout_view->addWidget(m_view); + QMainWindow::show(); +} + +void PrintViewWindow::setStartLineText(QString str) +{ + ui->lineEdit_start->setText(str); +} + +void PrintViewWindow::setNumberLineText(QString str) +{ + ui->lineEdit_number->setText(str); +} + +void PrintViewWindow::slotShowPoint(QPointF point) +{ + ui->lineEdit_x->setText(QString::number((int)point.x())+"mm"); + ui->lineEdit_y->setText(QString::number((int)point.y())+"mm"); +} + +void PrintViewWindow::on_pushButton_draw_clicked() +{ + m_startPoint = ui->lineEdit_start->text().toInt(); + m_printNumber = ui->lineEdit_number->text().toInt(); + + if(m_printNumber > 255 || m_printNumber <= 0 || m_startPoint < 0 || m_startPoint >= m_length) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Unreasonable value input!"),//数值输入不合理 + QMessageBox::Ok); + return; + } + + siAddNewFile(m_addNewFileFlag); + this->close(); +} diff --git a/printviewwindow.h b/printviewwindow.h new file mode 100644 index 0000000..950b263 --- /dev/null +++ b/printviewwindow.h @@ -0,0 +1,51 @@ +#ifndef PRINTVIEWWINDOW_H +#define PRINTVIEWWINDOW_H + +#include +#include +#include +#include +#include "datafile/view/mygraphicsview.h" +#include "machine/machine.h" +#include "main.h" + +namespace Ui { +class PrintViewWindow; +} + +class PrintViewWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit PrintViewWindow(QWidget *parent = 0); + ~PrintViewWindow(); + +private: + Ui::PrintViewWindow *ui; + + MyGraphicsView *m_view; + int m_startPoint; + int m_printNumber; + QString m_filePath; + int m_addNewFileFlag; + int m_length; + +public: + void refreshShow(McFilesInfo mcFilesInfo,int flag = 0); + void setStartLineText(QString str); + void setNumberLineText(QString str); + inline int getStartPoint(){return m_startPoint;} + inline int getPrintNumber(){return m_printNumber;} + +signals: + void siAddNewFile(int newFlag); + +public slots: + void slotShowPoint(QPointF point); + +private slots: + void on_pushButton_draw_clicked(); +}; + +#endif // PRINTVIEWWINDOW_H diff --git a/printviewwindow.ui b/printviewwindow.ui new file mode 100644 index 0000000..f58bb53 --- /dev/null +++ b/printviewwindow.ui @@ -0,0 +1,230 @@ + + + PrintViewWindow + + + + 0 + 0 + 1000 + 600 + + + + + 1000 + 600 + + + + Print View + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 1 + 20 + + + + + + + + + 770 + 32 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 440 + 0 + 21 + 31 + + + + mm + + + + + + 350 + 6 + 86 + 17 + + + + IBeamCursor + + + Qt::ClickFocus + + + 0 + + + QLineEdit::Normal + + + + + false + + + + 140 + 6 + 85 + 20 + + + + 0 + + + + + + 700 + 2 + 71 + 26 + + + + Draw + + + + + + 123 + 0 + 12 + 31 + + + + Y: + + + + + false + + + + 20 + 6 + 86 + 20 + + + + 0 + + + + + + 550 + 6 + 60 + 20 + + + + Qt::ClickFocus + + + 1 + + + + + + 243 + 0 + 101 + 31 + + + + Start point: + + + + + + 4 + 0 + 21 + 31 + + + + X: + + + + + + 480 + 0 + 61 + 31 + + + + Number: + + + label_startUnit + lineEdit_start + lineEdit_y + label_y + lineEdit_x + lineEdit_number + label_start + label_x + label_number + pushButton_draw + + + + + + + + + + + + diff --git a/res.qrc b/res.qrc new file mode 100644 index 0000000..f7814af --- /dev/null +++ b/res.qrc @@ -0,0 +1,20 @@ + + + resources/OpenFile.bmp + resources/pause.bmp + resources/start.bmp + resources/SetPara.bmp + resources/delete.bmp + resources/edit.bmp + resources/up.bmp + resources/down.bmp + resources/page_cx.bmp + resources/page_cy.bmp + resources/ErrorX.bmp + resources/ErrorY.bmp + resources/down_gap.bmp + resources/mark_gap.bmp + resources/right_ga.bmp + resources/OpenImage.png + + diff --git a/resources/ErrorX.bmp b/resources/ErrorX.bmp new file mode 100644 index 0000000000000000000000000000000000000000..077cb7467217a560ff6e9c1aede32fad1e3b041b GIT binary patch literal 1846 zcmeHII}U)Fd>N3Y@NO&-eKuWKoqzMtBwgYuQ)hv?JwrpJ)nf_TdMEB|WDP^G5-oTJQ3^NjfkvABbIG{W4Fz2+K#0RNUR!Db9YCCC@$!gVd>@!-N)RipcMh+OM zfKDwvhyVmc?nGq?Rb}>uHNea(lFN^L-wU5#EJn_xKW`5F{BB%kG3ZY`z;4dO7NtL* K^r!bV`Maosm_+md literal 0 HcmV?d00001 diff --git a/resources/OpenFile.bmp b/resources/OpenFile.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d91f82c58f55a2eeabaf6c5eba535e4938e2a155 GIT binary patch literal 1784 zcmeHFO=}ZD7>*Y&-aPpajN(NE5y4BnsXb^tC`!HbB8U|9AXpFu1wB|0QBl-VrQ5{j zqe+uCiD{c;^VP%{zlfzGnf;o56BCoB?e2Dyt&@$0klG@-2_5Dg-uIb#o|$=Oy1M1< z2E835qmjg}-?2^442B??-?^g^`a&|SZMFa30i~Q*N}}?UlM7k-$AX;yB0)-mIO%dB z^N;s~xd|~mBFsMKy>~d*RmOe+y*Zkt_GU+RvyRj1$|9s`b$M}fHAqZ~5i<@v<$d=! z_cdm`4~-p1)IMFLN2wGc9fqVA;yLJ4IPV?B#ZhqIIs`_7fo*TVb}x zaU2@bH@dFX)HbQy$M7Fp9`WAWoa+i>>qX|ShAm=rsQB$Oybr*f6VtEi8%^CHr^Rpk z+jKT6mw_vN&uCQ@(jiE=>;BI?=SZY zcA}rLoQCF7g{zu1f;2H0`TmK2R^T>Q8OYI?#NOS~u zcPnvyURp>tz+#5ZCvCatO9&2P|A64><6S3s*Rf{TYRY)evG>+iE3J5Exw@3=jJU;WI$$vT0@j~V9RL6T literal 0 HcmV?d00001 diff --git a/resources/OpenImage.png b/resources/OpenImage.png new file mode 100644 index 0000000000000000000000000000000000000000..6c7f8ac441d08ad27f8d0d364841a81af0dac7ae GIT binary patch literal 2083 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 Md5@edkkRG(7rJW%wg3PC literal 0 HcmV?d00001 diff --git a/resources/delete.bmp b/resources/delete.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9f31afce34418dc277a5537efb2f8a903312339b GIT binary patch literal 1784 zcmZWqOHUL*5MD1{ym|5`_zV02-aRWZ8ZRD=0Sp2fZa#~&rEl9*H>SCRWp0>QsHz+{$0TRJg#% z2%fmEU=TVf&+(byB>OTe7#)X@`Of%dch7aOAqj)IkB=uu3=#ni22pm3>ocbiGHXP1 zgyIGS*yWIUAwAB{E&W;5*OD=7?=XnVUd+TUh#%?M?d%-8E7}Z&sJ^y4*$F*Xz4+$w zTCz94w+nljKZz-}=I3(5J=uYl@1Od3%jcs&e0%@{>HV**VgU zq2NwB2TN6b*WH+Uk?OpjiBuX|Q*NX?H}cvXYF_BAGZXcqP>{(|15nDcMhd}I&4#5b zWf!9KZMu!1qE$;;^YTb|q3?k)c;B{ybm$xgxu84bM9zVLCZ|pY2rPEdHMEDR&WcRr zc6Q)NZn*3C*H74mfLFQUIWFvuu!9PMBZCX!pv22#eG9Q$>F_mTHSlP4q7Pb;3tEx- znQ{tP!H(hgEy)F7G#mP4vApu(*}^ zygV8=-?r-UI#at>v@Fspd;_v)2bxyKx(kOEk#SfYC8^}*acXEblz4eGx}-hRW3{FR zVP*f=9x6EBbw!T>>gn2K)Y?A+8TO)dl;8?^CuihFqDBHBHMyY%+d85&rR)%Qeez{G zTtP2Rf8&?wK~a?N=D$^=8lXn`!q<8J$ZHD2PVj^q~VU3{F#m%RT9(M8KSv zAQQ~h0fzOf2_q4v3YHb%STg88^2%ex1cT=PL9ruRj_Gm4lXrkni+&m;h*F7Mc)$U+AOurVTm13#zYlx{TU@VD=r6WbPIv$S literal 0 HcmV?d00001 diff --git a/resources/down.bmp b/resources/down.bmp new file mode 100644 index 0000000000000000000000000000000000000000..03a0525f88b6ec5c6dadc640bd80eb79e63be3c3 GIT binary patch literal 3944 zcmeHIOK%%h6b@?^NUZn)T_CYTh#e9_fRGSkQK<_QAr`y@;?bf)7ey>UMFJ!Q6{RYO zRwYpSi1TO?$97^naU3U39M_ItvFkYV@;p4(_KfGwd&XQlA;K`32r^=UdUWsT-0z(E zzR{U`&wc8JHy;@4+vDi@Fq+5q=6ypC_3=kh{K5NoXCFY1?mfF#fqz^9yKCFs?%&3r zLFE5sp!^l5L2~SE` zLc-$GPE6W~c53sT?SNPwgG9vAM0YXUvO4t|C?xsK7@v*unRz}PXlzV3QWK4}Q7(C% zT^V5$m)ZD_Z0sVl_$?FtijICxhd-s~Kc?r-)PpCfnb(N17wfabLh*{J@Gf$euCaHP z=wuKSR+^=iW-$(O5wIBo*;$a8=I=~4(!R#V4SxL^pZvM8`V*J9$St4e;$O3|FWAL% zTX&`?Do}1>VcPJddWr0)Kw-G;q$AS2rNyp49(J2OIIvSHdV=x1p_wsh6D`A z8xWXsb8kT2(q%(pn&}JJ%_k}U2}njd zseJaJ9E4kjE)sVkN7@!TBhCgk1Nh`AD)@=gs5oY*Tt+DV0*SDtwjC4pLA!7J%K^u> zTICI5{)e5hcdH{ONdH-_g$*Qlw*Xl`wRoM3T)`$ksQos){p&F4|4;>Yy;JBhp=JU$ z=h);Z$S?ERASxi2_>PO8uU>r~AAdy!TVBc8rU7yb?CQ8gZCOTFBC>S&oLC7N9hOUc zQ@->VcI&uIuN_^^RArD`V%Mf6s)R%lA^JzCDT&oE@{JB%4}G+C;aKh36H;yZh;pcb zfWoqf<mHGZCT4+leiqz{@e+VHqR626@Oe;UO z&uoa8RP!rL5}lcS@LxIT3L7xg1Id}wt(v6vw+4U-q^qKZ2jY51>o*#RuQ~0Q12o6CZq>ZyJ~QCdm>rW1>rzF?CCb zQ5+)>87Q3yg4>WV3N81RwzRDD_Kp_nk(!18T^im@*4%q@dhR*Dp8rYDwOjNOGkmVX zc?I_6e|v6dF-#Kf7v|kP41~kEcxLUunTF0(p0?{$IiYfeN=H;GQK=Z5XG#s6-bBfl z&G>U+cSZR4s1bS4*tuJOcZUlv;@DCU)M>3`%Di+CQA@GDMTg7m_XsT8)VT2VAe?Tq zCKZxu`J0&8>ipiH{BA&w_&uSPS*^lq<+Me#nK`XoqNl5q>7FNeJ!2f4T5qLanBt*} znwg{g-0h;OWoYQj>z>}?!Z(8Sc~V#B`jE4*%j}uS*(mnrF4&0I!2fA$YRERz{_$=C6_EM%Ale*k6f~!QVfG(S8{D+6# zdJ0AFPbIiczk1-7pksm#p&pyG8#_zgT1?J9@k5=%ffPe1LVuth%aH3^x7EU`9|v?P zr77d!#VbGFK!2bfg$+4_zULn^pdOL^guia%)W*oXFOSUoO)2wC$-Qz0gR$JvSDPB0 pYQdc^?I@xCinfc9cK)rBTUQR&5B> literal 0 HcmV?d00001 diff --git a/resources/mark_gap.bmp b/resources/mark_gap.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8529fae8c3dbb38c2b6915044a8a82c6a001a715 GIT binary patch literal 246 zcmZ?r{l)+RWk5;;hy|dSk%0v)(Eui~5kMJ`WJ3dl0+K)`!+`?_fHX+rKNvCm{|{mT jF%W`;fW!wV;D-WQ@fjF?{{KIpfr0fJ(v+w!sbHDiwyzKaU literal 0 HcmV?d00001 diff --git a/resources/page_cy.bmp b/resources/page_cy.bmp new file mode 100644 index 0000000000000000000000000000000000000000..86af6bd2a469b38c90f0b6597ce14bacd3ba6159 GIT binary patch literal 598 zcmcJLF%H5o3`Kttk}tpsx_~$aJ1gg?I<#vxV9MNytK=wLqf_`!8cL#c#Erk*=U-RK z<$Bv8#6UeU&&&g}!JZ1dn@}oZ03H|<3zaRLbF4b>;lO+Cn0ypbMvcce?%|!DQ0+_$ zWA+7~7XHflb4rnOyW!v5AJHD@fPtBzdl^`u5?cpah?qdFpiBD^*l6j}sz8N6NR?8l1t$<7 zDIv5|DT)G0q9!JZeRfg>k~of$eewCi*;LgP35XSl5b{ZPdcME?etOUEp560k^q$Ka z56Id@X6N78=DKg~cN4v%{cKtrWT`vD$$*mqDgziHSSc!Cza0BgO>Y`dro=inuv!3e zdQVOTs;p0!d0Mq=>#8cT5h3_CHQx&uH!LM-4@grByMB(D%zhpL%wRR`qgA^$(lm*U z3Y%||a}R;ntrZir2L!dkFMoDrGUFKr%a4^NSrE$EL@qpgxHKScJcrUD%`$4W<7f!1 zPxC9|;_Ao=7ob(UHnLdx@Z4oA|1{4`h(33dETd+|mEZYz5vv&81{O>34P66^yOgyb zCM>|b5WG)roORGbRx9JWt1RbzUDZd-vwVBbS1aqV<+Z_^J?d$bJ*t5||F8EBUjr)> z&uxET7yCv3C@iydHJRV9$QHl$nqPiK;!?N`TD5DFxGI@gF7%#V=(AWU+5@T5qezfn zo8rEX3Em+kyH2ZiZ8L{l;?IxyjAtLv^07#R>|M?T5e&);xVEr&Y3FZL+JvM9k literal 0 HcmV?d00001 diff --git a/resources/start.bmp b/resources/start.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f0b702a649ef4b902408670f85bdca21f9fa6063 GIT binary patch literal 3944 zcmeH|O>fgM7{|+*0}>}b00+(-_yCA&KLH0MP6#0w5^!K>JCyM<#3Z1+NZpuLRzM6W zl&x=D)1(WP=vun+I%yrOsqLm|>9)S6jpO2`lYpTiq$F^u6?-|^} zLNu@7CE&XtcuucAJG$bsetm3}UfXIYiko`fA}-AQl-F%IcO3?7)Ek1QPw~QuP2-tvc00ag^Zn%_sSVu`kuBxPSjS)RpS%>8V;UAu- z-ayQV7`a)9Pn5rKtumtX(|zhb`tl;3^A(;z5hr9Fh`lTFqs8RYjb*M;NGozhS0Y<2vsLh+SuUtp>Fmz$ zqxD7TU$Xd~lNN)O%sY84r!?!Gbo9-+-Pbg)4dGJ-EVXLuG@Y)~OkzEZ+f}WxNvr literal 0 HcmV?d00001 diff --git a/resources/up.bmp b/resources/up.bmp new file mode 100644 index 0000000000000000000000000000000000000000..479e835ae140618f0849c94c78944e80b966dce2 GIT binary patch literal 3944 zcmeH}%WoS+7{J4sLnTi90UWq+fCGXPQV$guP!$OY3Gujqdf*`h5(hx4xWEBaidqyE zwMrVIzLZBpT=@~lacVobcI-59ocR6Pr?b1>-I?{ScXqdYPO8w0SL;|rAhDWRjlTJP z-#0t^&G*geH_n|JJ9u7(_w&%7d)%KId-g#763jpI^kF{`!0XZf&wqah9E(^wCS7Fp zn@ajk?l(;)SRxuUkznDVwF%-0<_Y2mVoXGvYRi>DY2(Ga#A zo49zii7D=7xb$*6yRx5M-p}~ksYO0H%l~1*zq!D8Hic=RVl{2z#}qt zuM57^N^(RyUes-3(BVsJ^??_7M8+XKI`j*wr$@BoMIC%m!Jknh;{_g(IZ0o(sh`+) zSq46_{{`8pAM+;?hXe`i>Xm=ud_irsP3@8MciJ}R^qJ-#-_pyM_c!LDMh|7gJM0ic-kobLeM|>_5HfcO620plgS5J$ fQt(Tg3x?1*hWfB7kRRYojd+xXb^34S$Hx8w>uaYl literal 0 HcmV?d00001 diff --git a/startsetdialog.cpp b/startsetdialog.cpp new file mode 100644 index 0000000..b60b09c --- /dev/null +++ b/startsetdialog.cpp @@ -0,0 +1,50 @@ +#include "startsetdialog.h" +#include "ui_startsetdialog.h" + +StartSetDialog::StartSetDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::StartSetDialog) +{ + ui->setupUi(this); + setWindowModality(Qt::ApplicationModal); + setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); + m_startPoint = 0; + m_length = 0; + //整数 + QIntValidator *Validator = new QIntValidator(this); + ui->lineEdit_start->setValidator(Validator); +} + +StartSetDialog::~StartSetDialog() +{ + delete ui; +} + +int StartSetDialog::exec(QString title, QString text,QString length) +{ + ui->lineEdit_start->setText(text); + ui->label_range->setText("(0-"+length+")"); + m_length = length.toInt(); + m_startPoint = text.toInt(); + this->setWindowTitle(title); + return QDialog::exec(); +} + +void StartSetDialog::on_pushButton_ok_clicked() +{ + m_startPoint = ui->lineEdit_start->text().toInt(); + if(m_startPoint < 0 || m_startPoint >= m_length) + { + QMessageBox::warning(this, + tr("Prompt"), + tr("Unreasonable value input!"),//数值输入不合理 + QMessageBox::Ok); + return; + } + done(1); +} + +void StartSetDialog::on_pushButton_cancel_clicked() +{ + done(0); +} diff --git a/startsetdialog.h b/startsetdialog.h new file mode 100644 index 0000000..7ef61c2 --- /dev/null +++ b/startsetdialog.h @@ -0,0 +1,31 @@ +#ifndef STARTSETDIALOG_H +#define STARTSETDIALOG_H + +#include +#include + +namespace Ui { +class StartSetDialog; +} + +class StartSetDialog : public QDialog +{ + Q_OBJECT + +public: + explicit StartSetDialog(QWidget *parent = 0); + ~StartSetDialog(); + int exec(QString title,QString text,QString length); + inline int getStartPoint(){return m_startPoint;} + +private slots: + void on_pushButton_ok_clicked(); + void on_pushButton_cancel_clicked(); + +private: + Ui::StartSetDialog *ui; + int m_startPoint; + int m_length; +}; + +#endif // STARTSETDIALOG_H diff --git a/startsetdialog.ui b/startsetdialog.ui new file mode 100644 index 0000000..3ca9c56 --- /dev/null +++ b/startsetdialog.ui @@ -0,0 +1,84 @@ + + + StartSetDialog + + + + 0 + 0 + 345 + 107 + + + + Dialog + + + + + 200 + 68 + 60 + 26 + + + + Ok + + + + + + 270 + 68 + 60 + 26 + + + + Cancel + + + + + + 80 + 26 + 81 + 20 + + + + 0 + + + + + + 20 + 26 + 54 + 20 + + + + Start: + + + + + + 170 + 26 + 161 + 20 + + + + (range) + + + + + +