内容类型
个人空间
版块
Articles
Store
相册
Calendar
下载
博客
墨香年少 发布的所有帖子
-
1.创建React项目 npx create-react-app my-app 2.添加微软的FlumentUI yarn add @fluentui/react 或者 npm install @fluentui/react 3.添加路由 npm install react-router-dom@5.2.0 4.为了使用ajax yarn add axios 5.跨组件沟通事件 yarn add pubsub.js npm install pubsub-js --save 6.使用图表 npm install echarts --save 7.使用md5等加密 npm install crypto-js 8.开启项目 yarn start 9.编译 yaarn build 10.无刷新上传 npm install plupload@2.3.7
-
How to get user in TokenListener in symfony3.x? 1.打开文件: \vendor\symfony\symfony\src\Symfony\Component\Security\Core\Authorization\AuthorizationChecker.php 增加一个方法: final public function getUser() { return $this->tokenStorage->getToken()->getUser(); } 2.在TokenListener中 $user = $this->container->get('security.authorization_checker')->getUser(); 这样就可以获取到用户的信息了!
-
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp4 { public delegate void DelReadStdOutput(string result); public delegate void DelReadErrOutput(string result); public partial class Form1 : Form { public event DelReadStdOutput ReadStdOutput; public event DelReadErrOutput ReadErrOutput; public Form1() { InitializeComponent(); Init(); } private void Init() { //3.将相应函数注册到委托事件中 ReadStdOutput += new DelReadStdOutput(ReadStdOutputAction); ReadErrOutput += new DelReadErrOutput(ReadErrOutputAction); } private void RealAction(string StartFileName, string StartFileArg) { Process CmdProcess = new Process(); CmdProcess.StartInfo.FileName = StartFileName; // 命令 CmdProcess.StartInfo.Arguments = StartFileArg; // 参数 CmdProcess.StartInfo.CreateNoWindow = true; // 不创建新窗口 CmdProcess.StartInfo.UseShellExecute = false; CmdProcess.StartInfo.RedirectStandardInput = true; // 重定向输入 CmdProcess.StartInfo.RedirectStandardOutput = true; // 重定向标准输出 CmdProcess.StartInfo.RedirectStandardError = true; // 重定向错误输出 //CmdProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; CmdProcess.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived); CmdProcess.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived); CmdProcess.EnableRaisingEvents = true; // 启用Exited事件 CmdProcess.Exited += new EventHandler(CmdProcess_Exited); // 注册进程结束事件 CmdProcess.Start(); CmdProcess.BeginOutputReadLine(); CmdProcess.BeginErrorReadLine(); // 如果打开注释,则以同步方式执行命令,此例子中用Exited事件异步执行。 // CmdProcess.WaitForExit(); } private void p_OutputDataReceived(object sender, DataReceivedEventArgs e) { if (e.Data != null) { // 4. 异步调用,需要invoke this.Invoke(ReadStdOutput, new object[] { e.Data }); } } private void p_ErrorDataReceived(object sender, DataReceivedEventArgs e) { if (e.Data != null) { this.Invoke(ReadErrOutput, new object[] { e.Data }); } } private void ReadStdOutputAction(string result) { this.richTextBox1.AppendText(result + "\r\n"); } private void ReadErrOutputAction(string result) { this.richTextBox1.AppendText(result + "\r\n"); } private void CmdProcess_Exited(object sender, EventArgs e) { // 执行结束后触发 } private void button1_Click(object sender, EventArgs e) { RealAction("adb.exe", "devices"); } private void button2_Click(object sender, EventArgs e) { RealAction("adb.exe", "shell /system/bin/uiautomator dump --compressed /data/local/tmp/uidump.xml"); } private void button3_Click(object sender, EventArgs e) { RealAction("adb.exe", "pull /data/local/tmp/uidump.xml C:/Users/m/Desktop/DATA/uidump.xml"); } } }
-
官方下载链接:https://download3.vmware.com/software/wkst/file/VMware-workstation-full-15.0.0-10134415.exe 永久许可证:ZC10K-8EF57-084QZ-VXYXE-ZF2XF
-
#include <iostream> #include "Markup.h" using namespace std; int main() { CMarkup xml; xml.Load("D:\\PROJECTS\\TestXML\\Debug\\MyTest.xml"); BOOL findEle = xml.FindElem(); if (!findEle) { cerr << "can not find element!"; return 1; } xml.IntoElem(); //<Person name="duqingnian" age="36" address="江苏省" /> BOOL b = xml.FindElem("Person"); if (!b) { cout << "lost Person !!!" << endl; } cout << "name=" << xml.GetAttrib("name") << ", age=" << xml.GetAttrib("age") << ",addres=" << xml.GetAttrib("address") << endl;; if (true) { BOOL p = xml.FindElem("Phone"); if (!p) { cout << "lost phone!!" << endl; } xml.IntoElem(); xml.FindElem("Disk"); cout << xml.GetAttrib("size") << endl; } xml.OutOfElem(); //<Hello ID="HID">nihao</Hello> if (true) { BOOL a = xml.FindElem("Hello"); if (!a) { cout << "lost Hello!!" << endl; } cout << "data=" << xml.GetData() << ",id=" << xml.GetAttrib("ID") << endl; } cout << "over" << endl; return 0; } //XML /** <?xml version="1.0" encoding="UTF-8"?> <Window> <Person name="duqingnian" age="36" address="江苏省" /> <Phone> <Cpu stype="intel" /> <Memory size="16GB" /> <Disk size="512GB" type="固态" /> </Phone> <Hello ID="HID">nihao</Hello> </Window> */ //OUTPUT: /** name=duqingnian, age=36,addres=江苏省 512GB data=nihao,id=HID over */ CMarkup
-
Version 1.0.0
1 download
basic_form.h: #pragma once class BasicForm : public ui::WindowImplBase { public: BasicForm(); ~BasicForm(); virtual std::wstring GetSkinFolder() override; virtual std::wstring GetSkinFile() override; virtual std::wstring GetWindowClassName() const override; bool OnClicked(ui::EventArgs* msg); virtual void InitWindow() override; virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); static const std::wstring kClassName; ui::RichEdit* num; ui::RichEdit* zh_num; std::wstring string2wstring(std::string str); std::string wstring2string(std::wstring wstr); std::string ChineseCapitalMoney(double Num); }; basic_form.cpp: #include "framework.h" #include "basic_form.h" #include <string> #include <cstdlib> #include <atlstr.h> const std::wstring BasicForm::kClassName = L"Basic"; BasicForm::BasicForm() { } BasicForm::~BasicForm() { } std::wstring BasicForm::GetSkinFolder() { return L"basic"; } std::wstring BasicForm::GetSkinFile() { return L"basic.xml"; } std::wstring BasicForm::GetWindowClassName() const { return kClassName; } void BasicForm::InitWindow() { num = (ui::RichEdit*)FindControl(L"num"); zh_num = (ui::RichEdit*)FindControl(L"zh_num"); m_pRoot->AttachBubbledEvent(ui::kEventClick, nbase::Bind(&BasicForm::OnClicked, this, std::placeholders::_1)); } bool BasicForm::OnClicked(ui::EventArgs* msg) { std::wstring name = msg->pSender->GetName(); if (name == L"do_transe") { std::string _num = wstring2string(num->GetText()); double double_num = atof(_num.c_str()); std::string _cn_num = ChineseCapitalMoney(double_num); zh_num->SetText(string2wstring(_cn_num)); } else { } return true; } LRESULT BasicForm::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PostQuitMessage(0L); return __super::OnClose(uMsg, wParam, lParam, bHandled); } std::wstring BasicForm::string2wstring(std::string str) { std::wstring result; int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0); TCHAR* buffer = new TCHAR[len + 1]; MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len); buffer[len] = '\0'; result.append(buffer); delete[] buffer; return result; } std::string BasicForm::wstring2string(std::wstring wstr) { std::string result; int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); char* buffer = new char[len + 1]; WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL); buffer[len] = '\0'; result.append(buffer); delete[] buffer; return result; } std::string BasicForm::ChineseCapitalMoney(double Num) { std::string szChMoney; CString szNum; int iLen, iNum, iAddZero = 0; const char* hzUnit[18] = { "分","角","元","拾","佰","仟","万","拾","佰","仟","亿","拾","佰","仟","万","拾","佰","仟" }; const char* hzNum[10] = { "零","壹","贰","叁","肆","伍","陆","柒","捌","玖" }; szNum.Format(_T("%18.0f"), Num * 100); //只是到分 szNum.TrimLeft(); iLen = szNum.GetLength(); if (iLen > 15 || iLen == 0 || Num < 0)return ""; //数据错误返回 for (int i = 0; i < iLen; i++) { iNum = _ttoi((LPCTSTR)szNum.Mid(i, 1)); if (iNum == 0)//如果为0 iAddZero++; else { if (iAddZero > 0) szChMoney += "零"; szChMoney += hzNum[iNum];//转换为相应的数字 iAddZero = 0; } if (iNum != 0 || iLen - i == 3 || iLen - i == 11 || ((iLen - i + 1) % 8 == 0 && iAddZero < 4)) szChMoney += hzUnit[iLen - i - 1];//添加相应的汉字 } if (szNum.Right(2) == _T("00")) //没有角和分 szChMoney += "整"; return szChMoney; } -
Version 1.0.0
7 downloads
QrToPng.h: // // Created by remy on 07-06-20. // #ifndef QR_TO_PNG_H #define QR_TO_PNG_H #include "QrCode.hpp" #include "TinyPngOut.hpp" #include <fstream> #include <iostream> #include <memory> #include <string> #include <stdio.h> #include <io.h> class QrToPng { public: /** * Gives an object containing all the data to create the QR code. When @writeToPNG() is called, * the actual file is constructed and written. * The image is scaled to fit in the given size as much as possible relative to the QR code * size. * @param fileName relative or absolute filename to write image to. Relative will be in CWD. * @param imgSize The height and width of the image. Image is square, so will be width and height. * @param minModulePixelSize How many pixels big should a qr module be (a white or black dot)? * @param text The text to encode in the QR code. * @param overwriteExistingFile Overwrite if a file with @fileName already exists? * @param ecc error correction (low,mid,high). */ QrToPng(std::string fileName, int imgSize, int minModulePixelSize, std::string text, bool overwriteExistingFile, qrcodegen::QrCode::Ecc ecc); /** Writes a QrToPng object to a png file at @_fileName. * @return true if file could be written, false if file could not be written */ bool writeToPNG(); private: std::string _fileName; int _size; int _minModulePixelSize; std::string _text; bool _overwriteExistingFile; qrcodegen::QrCode::Ecc _ecc; bool _writeToPNG(const qrcodegen::QrCode &qrData) const; uint32_t _imgSize(const qrcodegen::QrCode &qrData) const; uint32_t _imgSizeWithBorder(const qrcodegen::QrCode &qrData) const; bool file_exists(std::string file_name) const; }; #endif //QR_TO_PNG_H QrToPng.cpp: // // Created by remy on 02-06-20. // #include "QrToPng.h" QrToPng::QrToPng(std::string fileName, int imgSize, int minModulePixelSize, std::string text, bool overwriteExistingFile, qrcodegen::QrCode::Ecc ecc) : _fileName(std::move(fileName)), _size(imgSize), _minModulePixelSize(minModulePixelSize), _text(std::move(text)), _overwriteExistingFile(overwriteExistingFile), _ecc(ecc) { } bool QrToPng::writeToPNG() { /* text is required */ if (_text.empty()) return false; if (!_overwriteExistingFile and file_exists(_fileName)) return false; auto _qr = qrcodegen::QrCode::encodeText("", _ecc); try { _qr = qrcodegen::QrCode::encodeText(_text.c_str(), _ecc); } catch (const std::length_error &e) { std::cerr << "Failed to generate QR code, too much data. Decrease _ecc, enlarge size or give less text." << std::endl; std::cerr << "e.what(): " << e.what() << std::endl; return false; } if (_overwriteExistingFile and file_exists(_fileName)) { /*if (!fs::copy_file(_fileName, _fileName + ".tmp", fs::copy_options::overwrite_existing)) { return false; }*/ } auto result = _writeToPNG(_qr); if (result) { std::string tmp_file(_fileName + ".tmp"); remove(tmp_file.c_str()); } return result; } bool QrToPng::_writeToPNG(const qrcodegen::QrCode &qrData) const { std::ofstream out(_fileName.c_str(), std::ios::binary); int pngWH = _imgSizeWithBorder(qrData); TinyPngOut pngout(pngWH, pngWH, out); auto qrSize = qrData.getSize(); auto qrSizeWithBorder = qrData.getSize() + 2; if (qrSizeWithBorder > _size) return false; // qrcode doesn't fit int qrSizeFitsInMaxImgSizeTimes = _size / qrSizeWithBorder; int pixelsWHPerModule = qrSizeFitsInMaxImgSizeTimes; if (qrSizeFitsInMaxImgSizeTimes < _minModulePixelSize) return false; // image would be to small to scan std::vector<uint8_t> tmpData; const uint8_t blackPixel = 0x00; const uint8_t whitePixel = 0xFF; /* The below loop converts the qrData to RGB8.8.8 pixels and writes it with * the tinyPNGoutput library. since we probably have requested a larger * qr module pixel size we must transform the qrData modules to be larger * pixels (than just 1x1). */ // border above for (int i = 0; i < pngWH; i++) // row for (int j = 0; j < pixelsWHPerModule; j++) // module pixel (height) tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel}); pngout.write(tmpData.data(), static_cast<size_t>(tmpData.size() / 3)); tmpData.clear(); for (int qrModuleAtY = 0; qrModuleAtY < qrSize; qrModuleAtY++) { for (int col = 0; col < pixelsWHPerModule; col++) { // border left for (int i = 0; i < qrSizeFitsInMaxImgSizeTimes; ++i) tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel}); // qr module to pixel for (int qrModuleAtX = 0; qrModuleAtX < (qrSize); qrModuleAtX++) { for (int row = 0; row < qrSizeFitsInMaxImgSizeTimes; ++row) { if (qrData.getModule(qrModuleAtX, qrModuleAtY)) { // insert saves us a for loop or 3 times the same line. tmpData.insert(tmpData.end(), {blackPixel, blackPixel, blackPixel}); } else { tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel}); } } } // border right for (int i = 0; i < qrSizeFitsInMaxImgSizeTimes; ++i) tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel}); // write the entire row pngout.write(tmpData.data(), static_cast<size_t>(tmpData.size() / 3)); tmpData.clear(); } } // border below for (int i = 0; i < pngWH; i++) // row for (int j = 0; j < pixelsWHPerModule; j++) // module pixel (height) tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel}); pngout.write(tmpData.data(), static_cast<size_t>(tmpData.size() / 3)); tmpData.clear(); return file_exists(_fileName); } uint32_t QrToPng::_imgSize(const qrcodegen::QrCode &qrData) const { return (_size / qrData.getSize()) * qrData.getSize(); } uint32_t QrToPng::_imgSizeWithBorder(const qrcodegen::QrCode &qrData) const { return (_size / (qrData.getSize() + 2)) * (qrData.getSize() + 2); } bool QrToPng::file_exists(std::string file_name) const { if ((_access(file_name.c_str(), 0) == 0) > 0) { return true; } return false; } TinyPngOut.hpp: /* * Tiny PNG Output (C++) * * Copyright (c) 2018 Project Nayuki * https://www.nayuki.io/page/tiny-png-output * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program (see COPYING.txt and COPYING.LESSER.txt). * If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <cstddef> #include <cstdint> #include <ostream> /* * Takes image pixel data in raw RGB8.8.8 format and writes a PNG file to a byte output stream. */ class TinyPngOut final { /*---- Fields ----*/ // Immutable configuration private: std::uint32_t width; // Measured in pixels private: std::uint32_t height; // Measured in pixels private: std::uint32_t lineSize; // Measured in bytes, equal to (width * 3 + 1) // Running state private: std::ostream &output; private: std::uint32_t positionX; // Next byte index in current line private: std::uint32_t positionY; // Line index of next byte private: std::uint32_t uncompRemain; // Number of uncompressed bytes remaining private: std::uint16_t deflateFilled; // Bytes filled in the current block (0 <= n < DEFLATE_MAX_BLOCK_SIZE) private: std::uint32_t crc; // Primarily for IDAT chunk private: std::uint32_t adler; // For DEFLATE data within IDAT /*---- Public constructor and method ----*/ /* * Creates a PNG writer with the given width and height (both non-zero) and byte output stream. * TinyPngOut will leave the output stream still open once it finishes writing the PNG file data. * Throws an exception if the dimensions exceed certain limits (e.g. w * h > 700 million). */ public: explicit TinyPngOut(std::uint32_t w, std::uint32_t h, std::ostream &out); /* * Writes 'count' pixels from the given array to the output stream. This reads count*3 * bytes from the array. Pixels are presented from top to bottom, left to right, and with * subpixels in RGB order. This object keeps track of how many pixels were written and * various position variables. It is an error to write more pixels in total than width*height. * Once exactly width*height pixels have been written with this TinyPngOut object, * there are no more valid operations on the object and it should be discarded. */ public: void write(const std::uint8_t pixels[], size_t count); /*---- Private checksum methods ----*/ // Reads the 'crc' field and updates its value based on the given array of new data. private: void crc32(const std::uint8_t data[], size_t len); // Reads the 'adler' field and updates its value based on the given array of new data. private: void adler32(const std::uint8_t data[], size_t len); /*---- Private utility members ----*/ private: template <std::size_t N> void write(const std::uint8_t(&data)[N]) { output.write(reinterpret_cast<const char*>(data), sizeof(data)); } private: static void putBigUint32(std::uint32_t val, std::uint8_t array[4]); private: static constexpr std::uint16_t DEFLATE_MAX_BLOCK_SIZE = 65535; }; TinyPngOut.cpp: /* * Tiny PNG Output (C++) * * Copyright (c) 2018 Project Nayuki * https://www.nayuki.io/page/tiny-png-output * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program (see COPYING.txt and COPYING.LESSER.txt). * If not, see <http://www.gnu.org/licenses/>. */ #include <algorithm> #include <cassert> #include <limits> #include <stdexcept> #include "TinyPngOut.hpp" using std::uint8_t; using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::size_t; TinyPngOut::TinyPngOut(uint32_t w, uint32_t h, std::ostream &out) : // Set most of the fields width(w), height(h), output(out), positionX(0), positionY(0), deflateFilled(0), adler(1) { // Check arguments if (width == 0 || height == 0) throw std::domain_error("Zero width or height"); // Compute and check data siezs uint64_t lineSz = static_cast<uint64_t>(width) * 3 + 1; if (lineSz > UINT32_MAX) throw std::length_error("Image too large"); lineSize = static_cast<uint32_t>(lineSz); uint64_t uncompRm = lineSize * height; if (uncompRm > UINT32_MAX) throw std::length_error("Image too large"); uncompRemain = static_cast<uint32_t>(uncompRm); uint32_t numBlocks = uncompRemain / DEFLATE_MAX_BLOCK_SIZE; if (uncompRemain % DEFLATE_MAX_BLOCK_SIZE != 0) numBlocks++; // Round up // 5 bytes per DEFLATE uncompressed block header, 2 bytes for zlib header, 4 bytes for zlib Adler-32 footer uint64_t idatSize = static_cast<uint64_t>(numBlocks) * 5 + 6; idatSize += uncompRemain; if (idatSize > static_cast<uint32_t>(INT32_MAX)) throw std::length_error("Image too large"); // Write header (not a pure header, but a couple of things concatenated together) uint8_t header[] = { // 43 bytes long // PNG header 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, // IHDR chunk 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0, 0, 0, 0, // 'width' placeholder 0, 0, 0, 0, // 'height' placeholder 0x08, 0x02, 0x00, 0x00, 0x00, 0, 0, 0, 0, // IHDR CRC-32 placeholder // IDAT chunk 0, 0, 0, 0, // 'idatSize' placeholder 0x49, 0x44, 0x41, 0x54, // DEFLATE data 0x08, 0x1D, }; putBigUint32(width, &header[16]); putBigUint32(height, &header[20]); putBigUint32(idatSize, &header[33]); crc = 0; crc32(&header[12], 17); putBigUint32(crc, &header[29]); write(header); crc = 0; crc32(&header[37], 6); // 0xD7245B6B } void TinyPngOut::write(const uint8_t pixels[], size_t count) { if (count > SIZE_MAX / 3) throw std::length_error("Invalid argument"); count *= 3; // Convert pixel count to byte count while (count > 0) { if (pixels == nullptr) throw std::invalid_argument("Null pointer"); if (positionY >= height) throw std::logic_error("All image pixels already written"); if (deflateFilled == 0) { // Start DEFLATE block uint16_t size = DEFLATE_MAX_BLOCK_SIZE; if (uncompRemain < size) size = static_cast<uint16_t>(uncompRemain); const uint8_t header[] = { // 5 bytes long static_cast<uint8_t>(uncompRemain <= DEFLATE_MAX_BLOCK_SIZE ? 1 : 0), static_cast<uint8_t>(size >> 0), static_cast<uint8_t>(size >> 8), static_cast<uint8_t>((size >> 0) ^ 0xFF), static_cast<uint8_t>((size >> 8) ^ 0xFF), }; write(header); crc32(header, sizeof(header) / sizeof(header[0])); } assert(positionX < lineSize && deflateFilled < DEFLATE_MAX_BLOCK_SIZE); if (positionX == 0) { // Beginning of line - write filter method byte uint8_t b[] = { 0 }; write(b); crc32(b, 1); adler32(b, 1); positionX++; uncompRemain--; deflateFilled++; } else { // Write some pixel bytes for current line uint16_t n = DEFLATE_MAX_BLOCK_SIZE - deflateFilled; if (lineSize - positionX < n) n = static_cast<uint16_t>(lineSize - positionX); if (count < n) n = static_cast<uint16_t>(count); if (static_cast<std::make_unsigned<std::streamsize>::type>(std::numeric_limits<std::streamsize>::max()) < std::numeric_limits<decltype(n)>::max()) n = std::min(n, static_cast<decltype(n)>(std::numeric_limits<std::streamsize>::max())); assert(n > 0); output.write(reinterpret_cast<const char*>(pixels), static_cast<std::streamsize>(n)); // Update checksums crc32(pixels, n); adler32(pixels, n); // Increment positions count -= n; pixels += n; positionX += n; uncompRemain -= n; deflateFilled += n; } if (deflateFilled >= DEFLATE_MAX_BLOCK_SIZE) deflateFilled = 0; // End current block if (positionX == lineSize) { // Increment line positionX = 0; positionY++; if (positionY == height) { // Reached end of pixels uint8_t footer[] = { // 20 bytes long 0, 0, 0, 0, // DEFLATE Adler-32 placeholder 0, 0, 0, 0, // IDAT CRC-32 placeholder // IEND chunk 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82, }; putBigUint32(adler, &footer[0]); crc32(&footer[0], 4); putBigUint32(crc, &footer[4]); write(footer); } } } } void TinyPngOut::crc32(const uint8_t data[], size_t len) { crc = ~crc; for (size_t i = 0; i < len; i++) { for (int j = 0; j < 8; j++) { // Inefficient bitwise implementation, instead of table-based uint32_t bit = (crc ^ (data[i] >> j)) & 1; crc = (crc >> 1) ^ ((-bit) & UINT32_C(0xEDB88320)); } } crc = ~crc; } void TinyPngOut::adler32(const uint8_t data[], size_t len) { uint32_t s1 = adler & 0xFFFF; uint32_t s2 = adler >> 16; for (size_t i = 0; i < len; i++) { s1 = (s1 + data[i]) % 65521; s2 = (s2 + s1) % 65521; } adler = s2 << 16 | s1; } void TinyPngOut::putBigUint32(uint32_t val, uint8_t array[4]) { for (int i = 0; i < 4; i++) array[i] = static_cast<uint8_t>(val >> ((3 - i) * 8)); } QrCode.hpp: /* * QR Code generator library (C++) * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other * liability, whether in an action of contract, tort or otherwise, arising from, * out of or in connection with the Software or the use or other dealings in the * Software. */ #pragma once #include <array> #include <cstdint> #include <stdexcept> #include <string> #include <vector> namespace qrcodegen { /* * A segment of character/binary/control data in a QR Code symbol. * Instances of this class are immutable. * The mid-level way to create a segment is to take the payload data * and call a static factory function such as QrSegment::makeNumeric(). * The low-level way to create a segment is to custom-make the bit buffer * and call the QrSegment() constructor with appropriate values. * This segment class imposes no length restrictions, but QR Codes have restrictions. * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. * Any segment longer than this is meaningless for the purpose of generating QR Codes. */ class QrSegment final { /*---- Public helper enumeration ----*/ /* * Describes how a segment's data bits are interpreted. Immutable. */ public: class Mode final { /*-- Constants --*/ public: static const Mode NUMERIC; public: static const Mode ALPHANUMERIC; public: static const Mode BYTE; public: static const Mode KANJI; public: static const Mode ECI; /*-- Fields --*/ // The mode indicator bits, which is a uint4 value (range 0 to 15). private: int modeBits; // Number of character count bits for three different version ranges. private: int numBitsCharCount[3]; /*-- Constructor --*/ private: Mode(int mode, int cc0, int cc1, int cc2); /*-- Methods --*/ /* * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15). */ public: int getModeBits() const; /* * (Package-private) Returns the bit width of the character count field for a segment in * this mode in a QR Code at the given version number. The result is in the range [0, 16]. */ public: int numCharCountBits(int ver) const; }; /*---- Static factory functions (mid level) ----*/ /* * Returns a segment representing the given binary data encoded in * byte mode. All input byte vectors are acceptable. Any text string * can be converted to UTF-8 bytes and encoded as a byte mode segment. */ public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data); /* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ public: static QrSegment makeNumeric(const char *digits); /* * Returns a segment representing the given text string encoded in alphanumeric mode. * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ public: static QrSegment makeAlphanumeric(const char *text); /* * Returns a list of zero or more segments to represent the given text string. The result * may use various segment modes and switch modes to optimize the length of the bit stream. */ public: static std::vector<QrSegment> makeSegments(const char *text); /* * Returns a segment representing an Extended Channel Interpretation * (ECI) designator with the given assignment value. */ public: static QrSegment makeEci(long assignVal); /*---- Public static helper functions ----*/ /* * Tests whether the given string can be encoded as a segment in alphanumeric mode. * A string is encodable iff each character is in the following set: 0 to 9, A to Z * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ public: static bool isAlphanumeric(const char *text); /* * Tests whether the given string can be encoded as a segment in numeric mode. * A string is encodable iff each character is in the range 0 to 9. */ public: static bool isNumeric(const char *text); /*---- Instance fields ----*/ /* The mode indicator of this segment. Accessed through getMode(). */ private: Mode mode; /* The length of this segment's unencoded data. Measured in characters for * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. * Always zero or positive. Not the same as the data's bit length. * Accessed through getNumChars(). */ private: int numChars; /* The data bits of this segment. Accessed through getData(). */ private: std::vector<bool> data; /*---- Constructors (low level) ----*/ /* * Creates a new QR Code segment with the given attributes and data. * The character count (numCh) must agree with the mode and the bit buffer length, * but the constraint isn't checked. The given bit buffer is copied and stored. */ public: QrSegment(Mode md, int numCh, const std::vector<bool> &dt); /* * Creates a new QR Code segment with the given parameters and data. * The character count (numCh) must agree with the mode and the bit buffer length, * but the constraint isn't checked. The given bit buffer is moved and stored. */ public: QrSegment(Mode md, int numCh, std::vector<bool> &&dt); /*---- Methods ----*/ /* * Returns the mode field of this segment. */ public: Mode getMode() const; /* * Returns the character count field of this segment. */ public: int getNumChars() const; /* * Returns the data bits of this segment. */ public: const std::vector<bool> &getData() const; // (Package-private) Calculates the number of bits needed to encode the given segments at // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. public: static int getTotalBits(const std::vector<QrSegment> &segs, int version); /*---- Private constant ----*/ /* The set of all legal characters in alphanumeric mode, where * each character value maps to the index in the string. */ private: static const char *ALPHANUMERIC_CHARSET; }; /* * A QR Code symbol, which is a type of two-dimension barcode. * Invented by Denso Wave and described in the ISO/IEC 18004 standard. * Instances of this class represent an immutable square grid of black and white cells. * The class provides static factory functions to create a QR Code from text or binary data. * The class covers the QR Code Model 2 specification, supporting all versions (sizes) * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. * * Ways to create a QR Code object: * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). * - Low level: Custom-make the array of data codeword bytes (including * segment headers and final padding, excluding error correction codewords), * supply the appropriate version number, and call the QrCode() constructor. * (Note that all ways require supplying the desired error correction level.) */ class QrCode final { /*---- Public helper enumeration ----*/ /* * The error correction level in a QR Code symbol. */ public: enum class Ecc { LOW = 0, // The QR Code can tolerate about 7% erroneous codewords MEDIUM, // The QR Code can tolerate about 15% erroneous codewords QUARTILE, // The QR Code can tolerate about 25% erroneous codewords HIGH, // The QR Code can tolerate about 30% erroneous codewords }; // Returns a value in the range 0 to 3 (unsigned 2-bit integer). private: static int getFormatBits(Ecc ecl); /*---- Static factory functions (high level) ----*/ /* * Returns a QR Code representing the given Unicode text string at the given error correction level. * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than * the ecl argument if it can be done without increasing the version. */ public: static QrCode encodeText(const char *text, Ecc ecl); /* * Returns a QR Code representing the given binary data at the given error correction level. * This function always encodes using the binary segment mode, not any text mode. The maximum number of * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. */ public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl); /*---- Static factory functions (mid level) ----*/ /* * Returns a QR Code representing the given segments with the given encoding parameters. * The smallest possible QR Code version within the given range is automatically * chosen for the output. Iff boostEcl is true, then the ECC level of the result * may be higher than the ecl argument if it can be done without increasing the * version. The mask number is either between 0 to 7 (inclusive) to force that * mask, or -1 to automatically choose an appropriate mask (which may be slow). * This function allows the user to create a custom sequence of segments that switches * between modes (such as alphanumeric and byte) to encode text in less space. * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). */ public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl, int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true); // All optional parameters /*---- Instance fields ----*/ // Immutable scalar parameters: /* The version number of this QR Code, which is between 1 and 40 (inclusive). * This determines the size of this barcode. */ private: int version; /* The width and height of this QR Code, measured in modules, between * 21 and 177 (inclusive). This is equal to version * 4 + 17. */ private: int size; /* The error correction level used in this QR Code. */ private: Ecc errorCorrectionLevel; /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). * Even if a QR Code is created with automatic masking requested (mask = -1), * the resulting object still has a mask value between 0 and 7. */ private: int mask; // Private grids of modules/pixels, with dimensions of size*size: // The modules of this QR Code (false = white, true = black). // Immutable after constructor finishes. Accessed through getModule(). private: std::vector<std::vector<bool> > modules; // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. private: std::vector<std::vector<bool> > isFunction; /*---- Constructor (low level) ----*/ /* * Creates a new QR Code with the given version number, * error correction level, data codeword bytes, and mask number. * This is a low-level API that most users should not use directly. * A mid-level API is the encodeSegments() function. */ public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk); /*---- Public instance methods ----*/ /* * Returns this QR Code's version, in the range [1, 40]. */ public: int getVersion() const; /* * Returns this QR Code's size, in the range [21, 177]. */ public: int getSize() const; /* * Returns this QR Code's error correction level. */ public: Ecc getErrorCorrectionLevel() const; /* * Returns this QR Code's mask, in the range [0, 7]. */ public: int getMask() const; /* * Returns the color of the module (pixel) at the given coordinates, which is false * for white or true for black. The top left corner has the coordinates (x=0, y=0). * If the given coordinates are out of bounds, then false (white) is returned. */ public: bool getModule(int x, int y) const; /* * Returns a string of SVG code for an image depicting this QR Code, with the given number * of border modules. The string always uses Unix newlines (\n), regardless of the platform. */ public: std::string toSvgString(int border) const; /*---- Private helper methods for constructor: Drawing function modules ----*/ // Reads this object's version field, and draws and marks all function modules. private: void drawFunctionPatterns(); // Draws two copies of the format bits (with its own error correction code) // based on the given mask and this object's error correction level field. private: void drawFormatBits(int msk); // Draws two copies of the version bits (with its own error correction code), // based on this object's version field, iff 7 <= version <= 40. private: void drawVersion(); // Draws a 9*9 finder pattern including the border separator, // with the center module at (x, y). Modules can be out of bounds. private: void drawFinderPattern(int x, int y); // Draws a 5*5 alignment pattern, with the center module // at (x, y). All modules must be in bounds. private: void drawAlignmentPattern(int x, int y); // Sets the color of a module and marks it as a function module. // Only used by the constructor. Coordinates must be in bounds. private: void setFunctionModule(int x, int y, bool isBlack); // Returns the color of the module at the given coordinates, which must be in range. private: bool module(int x, int y) const; /*---- Private helper methods for constructor: Codewords and masking ----*/ // Returns a new byte string representing the given data with the appropriate error correction // codewords appended to it, based on this object's version and error correction level. private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const; // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // data area of this QR Code. Function modules need to be marked off before this is called. private: void drawCodewords(const std::vector<std::uint8_t> &data); // XORs the codeword modules in this QR Code with the given mask pattern. // The function modules must be marked and the codeword bits must be drawn // before masking. Due to the arithmetic of XOR, calling applyMask() with // the same mask value a second time will undo the mask. A final well-formed // QR Code needs exactly one (not zero, two, etc.) mask applied. private: void applyMask(int msk); // Calculates and returns the penalty score based on state of this QR Code's current modules. // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. private: long getPenaltyScore() const; /*---- Private helper functions ----*/ // Returns an ascending list of positions of alignment patterns for this version number. // Each position is in the range [0,177), and are used on both the x and y axes. // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. private: std::vector<int> getAlignmentPatternPositions() const; // Returns the number of data bits that can be stored in a QR Code of the given version number, after // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. private: static int getNumRawDataModules(int ver); // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // QR Code of the given version number and error correction level, with remainder bits discarded. // This stateless pure function could be implemented as a (40*4)-cell lookup table. private: static int getNumDataCodewords(int ver, Ecc ecl); // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // implemented as a lookup table over all possible parameter values, instead of as an algorithm. private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree); // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor); // Returns the product of the two given field elements modulo GF(2^8/0x11D). // All inputs are valid. This could be implemented as a 256*256 lookup table. private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); // Can only be called immediately after a white run is added, and // returns either 0, 1, or 2. A helper function for getPenaltyScore(). private: int finderPenaltyCountPatterns(const std::array<int, 7> &runHistory) const; // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int, 7> &runHistory) const; // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). private: void finderPenaltyAddHistory(int currentRunLength, std::array<int, 7> &runHistory) const; // Returns true iff the i'th bit of x is set to 1. private: static bool getBit(long x, int i); /*---- Constants and tables ----*/ // The minimum version number supported in the QR Code Model 2 standard. public: static constexpr int MIN_VERSION = 1; // The maximum version number supported in the QR Code Model 2 standard. public: static constexpr int MAX_VERSION = 40; // For use in getPenaltyScore(), when evaluating which mask is best. private: static const int PENALTY_N1; private: static const int PENALTY_N2; private: static const int PENALTY_N3; private: static const int PENALTY_N4; private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; }; /*---- Public exception class ----*/ /* * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include: * - Decrease the error correction level if it was greater than Ecc::LOW. * - If the encodeSegments() function was called with a maxVersion argument, then increase * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other * factory functions because they search all versions up to QrCode::MAX_VERSION.) * - Split the text data into better or optimal segments in order to reduce the number of bits required. * - Change the text or binary data to be shorter. * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). * - Propagate the error upward to the caller/user. */ class data_too_long : public std::length_error { public: explicit data_too_long(const std::string &msg); }; /* * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. */ class BitBuffer final : public std::vector<bool> { /*---- Constructor ----*/ // Creates an empty bit buffer (length 0). public: BitBuffer(); /*---- Method ----*/ // Appends the given number of low-order bits of the given value // to this buffer. Requires 0 <= len <= 31 and val < 2^len. public: void appendBits(std::uint32_t val, int len); }; } QrCode.cpp: /* * QR Code generator library (C++) * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other * liability, whether in an action of contract, tort or otherwise, arising from, * out of or in connection with the Software or the use or other dealings in the * Software. */ #include <algorithm> #include <climits> #include <cstddef> #include <cstdlib> #include <cstring> #include <sstream> #include <stdexcept> #include <utility> #include "QrCode.hpp" using std::int8_t; using std::uint8_t; using std::size_t; using std::vector; namespace qrcodegen { QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : modeBits(mode) { numBitsCharCount[0] = cc0; numBitsCharCount[1] = cc1; numBitsCharCount[2] = cc2; } int QrSegment::Mode::getModeBits() const { return modeBits; } int QrSegment::Mode::numCharCountBits(int ver) const { return numBitsCharCount[(ver + 7) / 17]; } const QrSegment::Mode QrSegment::Mode::NUMERIC(0x1, 10, 12, 14); const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13); const QrSegment::Mode QrSegment::Mode::BYTE(0x4, 8, 16, 16); const QrSegment::Mode QrSegment::Mode::KANJI(0x8, 8, 10, 12); const QrSegment::Mode QrSegment::Mode::ECI(0x7, 0, 0, 0); QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) { if (data.size() > static_cast<unsigned int>(INT_MAX)) throw std::length_error("Data too long"); BitBuffer bb; for (uint8_t b : data) bb.appendBits(b, 8); return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb)); } QrSegment QrSegment::makeNumeric(const char *digits) { BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; for (; *digits != '\0'; digits++, charCount++) { char c = *digits; if (c < '0' || c > '9') throw std::domain_error("String contains non-numeric characters"); accumData = accumData * 10 + (c - '0'); accumCount++; if (accumCount == 3) { bb.appendBits(static_cast<uint32_t>(accumData), 10); accumData = 0; accumCount = 0; } } if (accumCount > 0) // 1 or 2 digits remaining bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1); return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); } QrSegment QrSegment::makeAlphanumeric(const char *text) { BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; for (; *text != '\0'; text++, charCount++) { const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); if (temp == nullptr) throw std::domain_error("String contains unencodable characters in alphanumeric mode"); accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET); accumCount++; if (accumCount == 2) { bb.appendBits(static_cast<uint32_t>(accumData), 11); accumData = 0; accumCount = 0; } } if (accumCount > 0) // 1 character remaining bb.appendBits(static_cast<uint32_t>(accumData), 6); return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); } vector<QrSegment> QrSegment::makeSegments(const char *text) { // Select the most efficient segment encoding automatically vector<QrSegment> result; if (*text == '\0'); // Leave result empty else if (isNumeric(text)) result.push_back(makeNumeric(text)); else if (isAlphanumeric(text)) result.push_back(makeAlphanumeric(text)); else { vector<uint8_t> bytes; for (; *text != '\0'; text++) bytes.push_back(static_cast<uint8_t>(*text)); result.push_back(makeBytes(bytes)); } return result; } QrSegment QrSegment::makeEci(long assignVal) { BitBuffer bb; if (assignVal < 0) throw std::domain_error("ECI assignment value out of range"); else if (assignVal < (1 << 7)) bb.appendBits(static_cast<uint32_t>(assignVal), 8); else if (assignVal < (1 << 14)) { bb.appendBits(2, 2); bb.appendBits(static_cast<uint32_t>(assignVal), 14); } else if (assignVal < 1000000L) { bb.appendBits(6, 3); bb.appendBits(static_cast<uint32_t>(assignVal), 21); } else throw std::domain_error("ECI assignment value out of range"); return QrSegment(Mode::ECI, 0, std::move(bb)); } QrSegment::QrSegment(Mode md, int numCh, const std::vector<bool> &dt) : mode(md), numChars(numCh), data(dt) { if (numCh < 0) throw std::domain_error("Invalid value"); } QrSegment::QrSegment(Mode md, int numCh, std::vector<bool> &&dt) : mode(md), numChars(numCh), data(std::move(dt)) { if (numCh < 0) throw std::domain_error("Invalid value"); } int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) { int result = 0; for (const QrSegment &seg : segs) { int ccbits = seg.mode.numCharCountBits(version); if (seg.numChars >= (1L << ccbits)) return -1; // The segment's length doesn't fit the field's bit width if (4 + ccbits > INT_MAX - result) return -1; // The sum will overflow an int type result += 4 + ccbits; if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result)) return -1; // The sum will overflow an int type result += static_cast<int>(seg.data.size()); } return result; } bool QrSegment::isAlphanumeric(const char *text) { for (; *text != '\0'; text++) { if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) return false; } return true; } bool QrSegment::isNumeric(const char *text) { for (; *text != '\0'; text++) { char c = *text; if (c < '0' || c > '9') return false; } return true; } QrSegment::Mode QrSegment::getMode() const { return mode; } int QrSegment::getNumChars() const { return numChars; } const std::vector<bool> &QrSegment::getData() const { return data; } const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; int QrCode::getFormatBits(Ecc ecl) { switch (ecl) { case Ecc::LOW: return 1; case Ecc::MEDIUM: return 0; case Ecc::QUARTILE: return 3; case Ecc::HIGH: return 2; default: throw std::logic_error("Assertion error"); } } QrCode QrCode::encodeText(const char *text, Ecc ecl) { vector<QrSegment> segs = QrSegment::makeSegments(text); return encodeSegments(segs, ecl); } QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) { vector<QrSegment> segs{ QrSegment::makeBytes(data) }; return encodeSegments(segs, ecl); } QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl, int minVersion, int maxVersion, int mask, bool boostEcl) { if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) throw std::invalid_argument("Invalid value"); // Find the minimal version number to use int version, dataUsedBits; for (version = minVersion; ; version++) { int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available dataUsedBits = QrSegment::getTotalBits(segs, version); if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable if (version >= maxVersion) { // All versions in the range could not fit the given data std::ostringstream sb; if (dataUsedBits == -1) sb << "Segment too long"; else { sb << "Data length = " << dataUsedBits << " bits, "; sb << "Max capacity = " << dataCapacityBits << " bits"; } throw data_too_long(sb.str()); } } if (dataUsedBits == -1) throw std::logic_error("Assertion error"); // Increase the error correction level while the data still fits in the current version number for (Ecc newEcl : vector<Ecc>{ Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH }) { // From low to high if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) ecl = newEcl; } // Concatenate all segments to create the data bit string BitBuffer bb; for (const QrSegment &seg : segs) { bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4); bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version)); bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); } if (bb.size() != static_cast<unsigned int>(dataUsedBits)) throw std::logic_error("Assertion error"); // Add terminator and pad up to a byte if applicable size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8; if (bb.size() > dataCapacityBits) throw std::logic_error("Assertion error"); bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size()))); bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8); if (bb.size() % 8 != 0) throw std::logic_error("Assertion error"); // Pad with alternating bytes until data capacity is reached for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) bb.appendBits(padByte, 8); // Pack bits into bytes in big endian vector<uint8_t> dataCodewords(bb.size() / 8); for (size_t i = 0; i < bb.size(); i++) dataCodewords[i >> 3] |= (bb.at(i) ? 1 : 0) << (7 - (i & 7)); // Create the QR Code object return QrCode(version, ecl, dataCodewords, mask); } QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) : // Initialize fields and check arguments version(ver), errorCorrectionLevel(ecl) { if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version value out of range"); if (msk < -1 || msk > 7) throw std::domain_error("Mask value out of range"); size = ver * 4 + 17; size_t sz = static_cast<size_t>(size); modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all white isFunction = vector<vector<bool> >(sz, vector<bool>(sz)); // Compute ECC, draw modules drawFunctionPatterns(); const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords); drawCodewords(allCodewords); // Do masking if (msk == -1) { // Automatically choose best mask long minPenalty = LONG_MAX; for (int i = 0; i < 8; i++) { applyMask(i); drawFormatBits(i); long penalty = getPenaltyScore(); if (penalty < minPenalty) { msk = i; minPenalty = penalty; } applyMask(i); // Undoes the mask due to XOR } } if (msk < 0 || msk > 7) throw std::logic_error("Assertion error"); this->mask = msk; applyMask(msk); // Apply the final choice of mask drawFormatBits(msk); // Overwrite old format bits isFunction.clear(); isFunction.shrink_to_fit(); } int QrCode::getVersion() const { return version; } int QrCode::getSize() const { return size; } QrCode::Ecc QrCode::getErrorCorrectionLevel() const { return errorCorrectionLevel; } int QrCode::getMask() const { return mask; } bool QrCode::getModule(int x, int y) const { return 0 <= x && x < size && 0 <= y && y < size && module(x, y); } std::string QrCode::toSvgString(int border) const { if (border < 0) throw std::domain_error("Border must be non-negative"); if (border > INT_MAX / 2 || border * 2 > INT_MAX - size) throw std::overflow_error("Border too large"); std::ostringstream sb; sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"; sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 "; sb << (size + border * 2) << " " << (size + border * 2) << "\" stroke=\"none\">\n"; sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n"; sb << "\t<path d=\""; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { if (getModule(x, y)) { if (x != 0 || y != 0) sb << " "; sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z"; } } } sb << "\" fill=\"#000000\"/>\n"; sb << "</svg>\n"; return sb.str(); } void QrCode::drawFunctionPatterns() { // Draw horizontal and vertical timing patterns for (int i = 0; i < size; i++) { setFunctionModule(6, i, i % 2 == 0); setFunctionModule(i, 6, i % 2 == 0); } // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) drawFinderPattern(3, 3); drawFinderPattern(size - 4, 3); drawFinderPattern(3, size - 4); // Draw numerous alignment patterns const vector<int> alignPatPos = getAlignmentPatternPositions(); size_t numAlign = alignPatPos.size(); for (size_t i = 0; i < numAlign; i++) { for (size_t j = 0; j < numAlign; j++) { // Don't draw on the three finder corners if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j)); } } // Draw configuration data drawFormatBits(0); // Dummy mask value; overwritten later in the constructor drawVersion(); } void QrCode::drawFormatBits(int msk) { // Calculate error correction code and pack bits int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 int rem = data; for (int i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >> 9) * 0x537); int bits = (data << 10 | rem) ^ 0x5412; // uint15 if (bits >> 15 != 0) throw std::logic_error("Assertion error"); // Draw first copy for (int i = 0; i <= 5; i++) setFunctionModule(8, i, getBit(bits, i)); setFunctionModule(8, 7, getBit(bits, 6)); setFunctionModule(8, 8, getBit(bits, 7)); setFunctionModule(7, 8, getBit(bits, 8)); for (int i = 9; i < 15; i++) setFunctionModule(14 - i, 8, getBit(bits, i)); // Draw second copy for (int i = 0; i < 8; i++) setFunctionModule(size - 1 - i, 8, getBit(bits, i)); for (int i = 8; i < 15; i++) setFunctionModule(8, size - 15 + i, getBit(bits, i)); setFunctionModule(8, size - 8, true); // Always black } void QrCode::drawVersion() { if (version < 7) return; // Calculate error correction code and pack bits int rem = version; // version is uint6, in the range [7, 40] for (int i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); long bits = static_cast<long>(version) << 12 | rem; // uint18 if (bits >> 18 != 0) throw std::logic_error("Assertion error"); // Draw two copies for (int i = 0; i < 18; i++) { bool bit = getBit(bits, i); int a = size - 11 + i % 3; int b = i / 3; setFunctionModule(a, b, bit); setFunctionModule(b, a, bit); } } void QrCode::drawFinderPattern(int x, int y) { for (int dy = -4; dy <= 4; dy++) { for (int dx = -4; dx <= 4; dx++) { int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm int xx = x + dx, yy = y + dy; if (0 <= xx && xx < size && 0 <= yy && yy < size) setFunctionModule(xx, yy, dist != 2 && dist != 4); } } } void QrCode::drawAlignmentPattern(int x, int y) { for (int dy = -2; dy <= 2; dy++) { for (int dx = -2; dx <= 2; dx++) setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); } } void QrCode::setFunctionModule(int x, int y, bool isBlack) { size_t ux = static_cast<size_t>(x); size_t uy = static_cast<size_t>(y); modules.at(uy).at(ux) = isBlack; isFunction.at(uy).at(ux) = true; } bool QrCode::module(int x, int y) const { return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x)); } vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const { if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel))) throw std::invalid_argument("Invalid argument"); // Calculate parameter numbers int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version]; int blockEccLen = ECC_CODEWORDS_PER_BLOCK[static_cast<int>(errorCorrectionLevel)][version]; int rawCodewords = getNumRawDataModules(version) / 8; int numShortBlocks = numBlocks - rawCodewords % numBlocks; int shortBlockLen = rawCodewords / numBlocks; // Split data into blocks and append ECC to each block vector<vector<uint8_t> > blocks; const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen); for (int i = 0, k = 0; i < numBlocks; i++) { vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast<int>(dat.size()); const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv); if (i < numShortBlocks) dat.push_back(0); dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); blocks.push_back(std::move(dat)); } // Interleave (not concatenate) the bytes from every block into a single sequence vector<uint8_t> result; for (size_t i = 0; i < blocks.at(0).size(); i++) { for (size_t j = 0; j < blocks.size(); j++) { // Skip the padding byte in short blocks if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks)) result.push_back(blocks.at(j).at(i)); } } if (result.size() != static_cast<unsigned int>(rawCodewords)) throw std::logic_error("Assertion error"); return result; } void QrCode::drawCodewords(const vector<uint8_t> &data) { if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8)) throw std::invalid_argument("Invalid argument"); size_t i = 0; // Bit index into the data // Do the funny zigzag scan for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair if (right == 6) right = 5; for (int vert = 0; vert < size; vert++) { // Vertical counter for (int j = 0; j < 2; j++) { size_t x = static_cast<size_t>(right - j); // Actual x coordinate bool upward = ((right + 1) & 2) == 0; size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert); // Actual y coordinate if (!isFunction.at(y).at(x) && i < data.size() * 8) { modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7)); i++; } // If this QR Code has any remainder bits (0 to 7), they were assigned as // 0/false/white by the constructor and are left unchanged by this method } } } if (i != data.size() * 8) throw std::logic_error("Assertion error"); } void QrCode::applyMask(int msk) { if (msk < 0 || msk > 7) throw std::domain_error("Mask value out of range"); size_t sz = static_cast<size_t>(size); for (size_t y = 0; y < sz; y++) { for (size_t x = 0; x < sz; x++) { bool invert; switch (msk) { case 0: invert = (x + y) % 2 == 0; break; case 1: invert = y % 2 == 0; break; case 2: invert = x % 3 == 0; break; case 3: invert = (x + y) % 3 == 0; break; case 4: invert = (x / 3 + y / 2) % 2 == 0; break; case 5: invert = x * y % 2 + x * y % 3 == 0; break; case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; default: throw std::logic_error("Assertion error"); } modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); } } } long QrCode::getPenaltyScore() const { long result = 0; // Adjacent modules in row having same color, and finder-like patterns for (int y = 0; y < size; y++) { bool runColor = false; int runX = 0; std::array<int, 7> runHistory = {}; for (int x = 0; x < size; x++) { if (module(x, y) == runColor) { runX++; if (runX == 5) result += PENALTY_N1; else if (runX > 5) result++; } else { finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runX = 1; } } result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns for (int x = 0; x < size; x++) { bool runColor = false; int runY = 0; std::array<int, 7> runHistory = {}; for (int y = 0; y < size; y++) { if (module(x, y) == runColor) { runY++; if (runY == 5) result += PENALTY_N1; else if (runY > 5) result++; } else { finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; runColor = module(x, y); runY = 1; } } result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; } // 2*2 blocks of modules having same color for (int y = 0; y < size - 1; y++) { for (int x = 0; x < size - 1; x++) { bool color = module(x, y); if (color == module(x + 1, y) && color == module(x, y + 1) && color == module(x + 1, y + 1)) result += PENALTY_N2; } } // Balance of black and white modules int black = 0; for (const vector<bool> &row : modules) { for (bool color : row) { if (color) black++; } } int total = size * size; // Note that size is odd, so black/total != 1/2 // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% int k = static_cast<int>((std::abs(black * 20L - total * 10L) + total - 1) / total) - 1; result += k * PENALTY_N4; return result; } vector<int> QrCode::getAlignmentPatternPositions() const { if (version == 1) return vector<int>(); else { int numAlign = version / 7 + 2; int step = (version == 32) ? 26 : (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; vector<int> result; for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) result.insert(result.begin(), pos); result.insert(result.begin(), 6); return result; } } int QrCode::getNumRawDataModules(int ver) { if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version number out of range"); int result = (16 * ver + 128) * ver + 64; if (ver >= 2) { int numAlign = ver / 7 + 2; result -= (25 * numAlign - 10) * numAlign - 55; if (ver >= 7) result -= 36; } if (!(208 <= result && result <= 29648)) throw std::logic_error("Assertion error"); return result; } int QrCode::getNumDataCodewords(int ver, Ecc ecl) { return getNumRawDataModules(ver) / 8 - ECC_CODEWORDS_PER_BLOCK[static_cast<int>(ecl)][ver] * NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver]; } vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) { if (degree < 1 || degree > 255) throw std::domain_error("Degree out of range"); // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. vector<uint8_t> result(static_cast<size_t>(degree)); result.at(result.size() - 1) = 1; // Start off with the monomial x^0 // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), // and drop the highest monomial term which is always 1x^degree. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). uint8_t root = 1; for (int i = 0; i < degree; i++) { // Multiply the current product by (x - r^i) for (size_t j = 0; j < result.size(); j++) { result.at(j) = reedSolomonMultiply(result.at(j), root); if (j + 1 < result.size()) result.at(j) ^= result.at(j + 1); } root = reedSolomonMultiply(root, 0x02); } return result; } vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) { vector<uint8_t> result(divisor.size()); for (uint8_t b : data) { // Polynomial division uint8_t factor = b ^ result.at(0); result.erase(result.begin()); result.push_back(0); for (size_t i = 0; i < result.size(); i++) result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor); } return result; } uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { // Russian peasant multiplication int z = 0; for (int i = 7; i >= 0; i--) { z = (z << 1) ^ ((z >> 7) * 0x11D); z ^= ((y >> i) & 1) * x; } if (z >> 8 != 0) throw std::logic_error("Assertion error"); return static_cast<uint8_t>(z); } int QrCode::finderPenaltyCountPatterns(const std::array<int, 7> &runHistory) const { int n = runHistory.at(1); if (n > size * 3) throw std::logic_error("Assertion error"); bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); } int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int, 7> &runHistory) const { if (currentRunColor) { // Terminate black run finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; } currentRunLength += size; // Add white border to final run finderPenaltyAddHistory(currentRunLength, runHistory); return finderPenaltyCountPatterns(runHistory); } void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int, 7> &runHistory) const { if (runHistory.at(0) == 0) currentRunLength += size; // Add white border to initial run std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); runHistory.at(0) = currentRunLength; } bool QrCode::getBit(long x, int i) { return ((x >> i) & 1) != 0; } /*---- Tables of constants ----*/ const int QrCode::PENALTY_N1 = 3; const int QrCode::PENALTY_N2 = 3; const int QrCode::PENALTY_N3 = 40; const int QrCode::PENALTY_N4 = 10; const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 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, 36, 37, 38, 39, 40 Error correction level {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High }; const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,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, 36, 37, 38, 39, 40 Error correction level {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High }; data_too_long::data_too_long(const std::string &msg) : std::length_error(msg) {} BitBuffer::BitBuffer() : std::vector<bool>() {} void BitBuffer::appendBits(std::uint32_t val, int len) { if (len < 0 || len > 31 || val >> len != 0) throw std::domain_error("Value out of range"); for (int i = len - 1; i >= 0; i--) // Append bit by bit this->push_back(((val >> i) & 1) != 0); } } basic_form.h: #pragma once class BasicForm : public ui::WindowImplBase { public: BasicForm(); ~BasicForm(); /** * 一下三个接口是必须要覆写的接口,父类会调用这三个接口来构建窗口 * GetSkinFolder 接口设置你要绘制的窗口皮肤资源路径 * GetSkinFile 接口设置你要绘制的窗口的 xml 描述文件 * GetWindowClassName 接口设置窗口唯一的类名称 */ virtual std::wstring GetSkinFolder() override; virtual std::wstring GetSkinFile() override; virtual std::wstring GetWindowClassName() const override; bool OnClicked(ui::EventArgs* msg); bool Notify(ui::EventArgs* msg); /** * 收到 WM_CREATE 消息时该函数会被调用,通常做一些控件初始化的操作 */ virtual void InitWindow() override; std::wstring string2wstring(std::string str); std::string wstring2string(std::wstring wstr); std::string random_string(size_t length); char *rand_str(char *str, const int len); void copy_file(const char* srce_file, const char* dest_file); /** * 收到 WM_CLOSE 消息时该函数会被调用 */ virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); bool ExplorerGoTo(const std::wstring &Path); void string_replace(std::string &strBig, const std::string &strsrc, const std::string &strdst); bool OpenFolder(HWND hwndOwner/*=NULL*/, CString& strFolder); std::string GetSaveFile(char* initDirectory = NULL); static const std::wstring kClassName; ui::RichEdit* words; ui::Label* qrcode_preview; ui::Button* open_qrcode; std::string curr_folder; std::string qrcode_file; }; basic_form.cpp: #include "framework.h" #include "basic_form.h" ///////////////////// #include <cstddef> #include <fstream> #include <cstdint> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include "QrCode.hpp" #include "TinyPngOut.hpp" #include "QrToPng.h" #include "Text.h" #include "shellapi.h" #include <shlobj.h> #include "commdlg.h" #include <time.h> #include <fstream> using std::uint8_t; using qrcodegen::QrCode; using qrcodegen::QrSegment; using std::uint32_t; using std::size_t; ///////////////////// const std::wstring BasicForm::kClassName = L"Basic"; BasicForm::BasicForm() { } BasicForm::~BasicForm() { } std::wstring BasicForm::GetSkinFolder() { return L"basic"; } std::wstring BasicForm::GetSkinFile() { return L"basic.xml"; } std::wstring BasicForm::GetWindowClassName() const { return kClassName; } void BasicForm::InitWindow() { //获取exe执行路径 TCHAR _szPath[MAX_PATH] = { 0 }; if (!GetModuleFileName(NULL, _szPath, MAX_PATH)) { return; } (_tcsrchr(_szPath, _T('\\')))[1] = 0;//删除文件名,只获得路径 字串 CString strPath; for (int n = 0; _szPath[n]; n++) { if (_szPath[n] != _T('\\')) { strPath += _szPath[n]; } else { strPath += _T("\\\\"); } } curr_folder = CW2A(strPath.GetString()); string_replace(curr_folder, "\\\\", "\\"); string_replace(curr_folder, "/", "\\"); std::string img_path = curr_folder + "IMG\\"; LPCWSTR _IMG = (LPCWSTR)img_path.c_str(); if (GetFileAttributes(L"IMG") != FILE_ATTRIBUTE_DIRECTORY) { if (!::CreateDirectory(L"IMG", NULL)) { char szDir[MAX_PATH]; std::string tip = "创建目录[IMG]失败,请检查权限"; MessageBoxA(NULL, tip.c_str(), "提示", MB_OK | MB_ICONERROR); } } //获取控件 words = (ui::RichEdit*)FindControl(L"words"); qrcode_preview = (ui::Label*)FindControl(L"qrcode_preview"); open_qrcode = (ui::Button*)FindControl(L"open_qrcode"); m_pRoot->AttachBubbledEvent(ui::kEventClick, nbase::Bind(&BasicForm::OnClicked, this, std::placeholders::_1)); m_pRoot->AttachBubbledEvent(ui::kEventAll, nbase::Bind(&BasicForm::Notify, this, std::placeholders::_1)); } LRESULT BasicForm::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PostQuitMessage(0L); return __super::OnClose(uMsg, wParam, lParam, bHandled); } bool BasicForm::Notify(ui::EventArgs* msg) { //std::wstring name = msg->pSender->GetName(); if (msg->Type == ui::kEventMouseRightButtonUp) { } return true; } bool BasicForm::OnClicked(ui::EventArgs* msg) { std::wstring name = msg->pSender->GetName(); if (name == L"btn_generate") { std::wstring _ws = words->GetText(); std::string qrText = wstring2string(_ws); char name[10] = {0}; rand_str(name, 8); std::string _name(name); std::string fileName = _name + ".png"; //首先判断 需要生成的文本是不是为空 std::string _ww = wstring2string(_ws); trim(_ww); words->SetText(string2wstring(_ww)); if (_ww == "") { MessageBoxA(NULL, "请输入要生成的文字!", "提示", 0); words->SetFocus(); return true; } int imgSize = 500; int minModulePixelSize = 1; auto exampleQrPng1 = QrToPng("IMG/"+fileName, imgSize, minModulePixelSize, qrText, true, qrcodegen::QrCode::Ecc::MEDIUM); if (exampleQrPng1.writeToPNG()) { qrcode_file = curr_folder +"IMG/"+ fileName; if ((access(qrcode_file.c_str(), 0) == 0) > 0) { std::wstring qf = string2wstring(qrcode_file); qrcode_preview->SetBkImage(qf); } } else { MessageBoxA(NULL, "生成失败!", "错误", 0); } } else if (L"open_qrcode" == name) { string_replace(qrcode_file,"\\\\","\\"); string_replace(qrcode_file, "/", "\\"); std::wstring wpath = string2wstring(qrcode_file); //words->SetText(wpath); ExplorerGoTo(wpath); } else if (L"save_qrcode" == name) { std::string save_file = GetSaveFile(); std::wstring _save_file = string2wstring(save_file); string_replace(qrcode_file, "\\\\", "\\"); string_replace(qrcode_file, "/", "\\"); //拷贝 copy_file(qrcode_file.c_str(), (wstring2string(_save_file)).c_str()); MessageBoxA(NULL, "操作成功", "提示", 0); } else { } return true; } char * BasicForm::rand_str(char *str, const int len) { srand(time(NULL)); int i; for (i = 0; i < len; ++i) { switch ((rand() % 3)) { case 1: str[i] = 'A' + rand() % 26; break; case 2: str[i] = 'a' + rand() % 26; break; default: str[i] = '0' + rand() % 10; break; } } str[++i] = '\0'; return str; } void BasicForm::copy_file(const char* srce_file, const char* dest_file) { std::ifstream srce(srce_file, std::ios::binary); std::ofstream dest(dest_file, std::ios::binary); dest << srce.rdbuf(); } std::string BasicForm::GetSaveFile(char* initDirectory) { //文件名 std::string filename; //打开文件 OPENFILENAME ofn = { 0 }; TCHAR strFilename[MAX_PATH] = { 0 };//用于接收文件名 ofn.lStructSize = sizeof(OPENFILENAME);//结构体大小 ofn.hwndOwner = GetForegroundWindow();//拥有着窗口句柄 ofn.lpstrFilter = TEXT("二维码图像\0*.png\0\0");//设置过滤 ofn.nFilterIndex = 1;//过滤器索引 ofn.lpstrFile = strFilename;//接收返回的文件名,注意第一个字符需要为NULL ofn.nMaxFile = sizeof(strFilename);//缓冲区长度 ofn.lpstrInitialDir = (LPCWSTR)initDirectory;//初始目录为默认 //对话框标题 ofn.lpstrTitle = TEXT("请选择一个文件"); ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;//目录必须存在,覆盖文件前发出警告 ofn.lpstrDefExt = TEXT("png");//默认追加的扩展名 if (GetSaveFileName(&ofn)) { CString str(ofn.lpstrFile); filename = CW2A(str.GetString()); } return filename; } bool BasicForm::OpenFolder(HWND hwndOwner/*=NULL*/, CString& strFolder) { //选择文件夹 BROWSEINFO info; info.hwndOwner = hwndOwner; info.pidlRoot = NULL; info.pszDisplayName = NULL; info.lpszTitle = _T("请选择路径"); info.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI; info.lpfn = NULL; info.iImage = 0; LPCITEMIDLIST pidl = SHBrowseForFolder(&info); if (!pidl) return false; TCHAR szDisplayName[255]; SHGetPathFromIDList(pidl, szDisplayName); strFolder = szDisplayName; //因为不确定传入的路径是否包含\,所以先删除再进行添加 strFolder.TrimRight(_T("\\")); strFolder += _T("\\"); return true; } void BasicForm::string_replace(std::string &strBig, const std::string &strsrc, const std::string &strdst) { std::string::size_type pos = 0; std::string::size_type srclen = strsrc.size(); std::string::size_type dstlen = strdst.size(); while ((pos = strBig.find(strsrc, pos)) != std::string::npos) { strBig.replace(pos, srclen, strdst); pos += dstlen; } } bool BasicForm::ExplorerGoTo(const std::wstring &Path) { TCHAR tcBuff[8] = { 0 }; lstrcpyn(tcBuff, Path.c_str(), 5); std::wstring stParams = _T("/n, /select, "); if (lstrcmpi(_T("\\??\\"), tcBuff) == 0) { stParams += (Path[4]); } else { stParams += Path; } std::wstring stExplorer = _T("C:\\Windows\\explorer.exe"); if (stExplorer.empty()) stExplorer = _T("explorer.exe"); SHELLEXECUTEINFO shi = { 0 }; shi.cbSize = sizeof(SHELLEXECUTEINFO); shi.lpVerb = _T("open"); shi.lpFile = stExplorer.c_str(); shi.lpParameters = stParams.c_str(); shi.nShow = SW_SHOW; bool bRes = ShellExecuteEx(&shi); if (bRes == FALSE && GetLastError() != 0) { Sleep(200); return ShellExecuteEx(&shi); } return bRes; } std::string BasicForm::random_string(size_t length) { auto randchar = []() -> char { const char charset[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; const size_t max_index = (sizeof(charset) - 1); return charset[rand() % max_index]; }; std::string str(length, 0); std::generate_n(str.begin(), length, randchar); return str; } std::wstring BasicForm::string2wstring(std::string str) { std::wstring result; //获取缓冲区大小,并申请空间,缓冲区大小按字符计算 int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0); TCHAR* buffer = new TCHAR[len + 1]; //多字节编码转换成宽字节编码 MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len); buffer[len] = '\0'; //添加字符串结尾 //删除缓冲区并返回值 result.append(buffer); delete[] buffer; return result; } //将wstring转换成string std::string BasicForm::wstring2string(std::wstring wstr) { std::string result; //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的 int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); char* buffer = new char[len + 1]; //宽字节编码转换成多字节编码 WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL); buffer[len] = '\0'; //删除缓冲区并返回值 result.append(buffer); delete[] buffer; return result; } Text.cpp: #include <algorithm> #include <functional> #include <cctype> #include <locale> #include "Text.h" int my_isspace(int ch) { return (unsigned int)(ch - 9) < 5u || ch == ' '; } std::string& ltrim(std::string &ss) { std::string::iterator it = ss.begin(); std::string::iterator end = ss.end(); while (it != end && my_isspace(*it)) ++it; ss.erase(ss.begin(), it); return ss; } std::string& rtrim(std::string &ss) { int pos = int(ss.size()) - 1; while (pos >= 0 && my_isspace(ss[pos])) --pos; ss.resize(pos + 1); return ss; } std::string& trim(std::string &st) { ltrim(rtrim(st)); return st; } -
ZF3R0-FHED2-M80TY-8QYGC-NPKYF YF390-0HF8P-M81RQ-2DXQE-M2UT6 ZF71R-DMX85-08DQY-8YMNC-PPHV8
-
ZF3R0-FHED2-M80TY-8QYGC-NPKYF YF390-0HF8P-M81RQ-2DXQE-M2UT6 ZF71R-DMX85-08DQY-8YMNC-PPHV8
-
尝试运行xmodmap -e 'keycode 24='以仅禁用Q键。如果可行,您可以将其添加到~/.bashrc或全局/etc/bash.bashrc文件中。 Q: How can I disable one or several keys on my laptop keyboard in Linux? When I press the DELETE key, it gets stuck and deletes everything A: No problem! You can use the following command to remap or disable any key of your keyboard: xmodmap -e 'keycode <value>=<action>' For example, you could run the following command to disable your DELETE key: xmodmap -e 'keycode 107=' How to get the correct keycode You can get the keycode that corresponds to a specific keyboard button in one of two ways. The first method is by using the simple command xev. xev opens a window and then monitors “events” such as keystrokes. It is suitable when you are running a GUI. The second method, which can be run with only the console, is showkey. This command will monitor for keystrokes for 10 seconds, or until a SIGTERM signal is received. List of all keycodes The full list of available keycodes and actions assigned to them on UK keyboard is below… keycode 8 = keycode 9 = Escape keycode 10 = 1 exclam keycode 11 = 2 quotedbl keycode 12 = 3 sterling keycode 13 = 4 dollar keycode 14 = 5 percent keycode 15 = 6 asciicircum keycode 16 = 7 ampersand keycode 17 = 8 asterisk keycode 18 = 9 parenleft keycode 19 = 0 parenright keycode 20 = minus underscore keycode 21 = equal plus keycode 22 = Delete keycode 23 = Tab keycode 24 = Q keycode 25 = W keycode 26 = E keycode 27 = R keycode 28 = T keycode 29 = Y keycode 30 = U keycode 31 = I keycode 32 = O keycode 33 = P keycode 34 = bracketleft braceleft keycode 35 = bracketright braceright keycode 36 = Return keycode 37 = Control_L keycode 38 = A keycode 39 = S keycode 40 = D keycode 41 = F keycode 42 = G keycode 43 = H keycode 44 = J keycode 45 = K keycode 46 = L keycode 47 = semicolon colon keycode 48 = apostrophe at keycode 49 = grave asciitilde keycode 50 = Shift_L keycode 51 = numbersign asciitilde keycode 52 = Z keycode 53 = X keycode 54 = C keycode 55 = V keycode 56 = B keycode 57 = N keycode 58 = M keycode 59 = comma less keycode 60 = period greater keycode 61 = slash question keycode 62 = Shift_R keycode 63 = KP_Multiply keycode 64 = Alt_L keycode 65 = space keycode 66 = Caps_Lock keycode 67 = F1 keycode 68 = F2 keycode 69 = F3 keycode 70 = F4 keycode 71 = F5 keycode 72 = F6 keycode 73 = F7 keycode 74 = F8 keycode 75 = F9 keycode 76 = F10 keycode 77 = Num_Lock keycode 78 = Scroll_Lock keycode 79 = Home KP_7 KP_7 Home keycode 80 = Up KP_8 KP_8 Up keycode 81 = Prior KP_9 KP_9 Prior keycode 82 = KP_Subtract keycode 83 = Left KP_4 KP_4 Left keycode 84 = Begin KP_5 KP_5 Begin keycode 85 = Right KP_6 KP_6 Right keycode 86 = KP_Add keycode 87 = End KP_1 KP_1 End keycode 88 = Down KP_2 KP_2 Down keycode 89 = Next KP_3 KP_3 Next keycode 90 = Insert KP_0 KP_0 Insert keycode 91 = Delete KP_Decimal KP_Decimal Delete keycode 92 = 0x1007ff00 keycode 93 = keycode 94 = backslash bar keycode 95 = F11 keycode 96 = F12 keycode 97 = Home keycode 98 = Up keycode 99 = Prior keycode 100 = Left keycode 101 = Begin keycode 102 = Right keycode 103 = End keycode 104 = Down keycode 105 = Next keycode 106 = Insert keycode 107 = Delete keycode 108 = KP_Enter keycode 109 = Control_R keycode 110 = Pause keycode 111 = Print keycode 112 = KP_Divide keycode 113 = Mode_switch keycode 114 = Break
-
tmp sln: xinput list 列出列表,找到自带键盘的id 然后执行 xinput set-prop id "Device Enabled" 0 我的电脑自带键盘id为14:,所以如图: this sln is tmp,if you reboot your conputer , you must do this again. so, if you want do something once, your keyboard disable for ever,read this: 打开终端并运行以下命令 $sudo gedit /etc/default/grub 找到以下行 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 添加参数i8042.nokbd,上面的行应该是这样的 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i8042.nokbd" 按以下命令更新grub $sudo update-grub 然后reboot你的笔记本电脑
-
Version 1.0.0
22 downloads
/* Copyright (c) 2011, Aurelien Aptel <aurelien.aptel@gmail.com> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <string> #include <fstream> #include <iostream> #include <cstdlib> #include <vector> using namespace std; typedef unsigned char uchar; #define PW_MAGIC 0xA3 #define PW_MAXLEN 50 #define PW_FLAG 0xFF string decrypt(string pwd, string key); #ifdef WIN #include <windows.h> #define REG_MAXLEN_KEY 255 #define REG_MAXLEN_VAL 16383 const string session_path = TEXT("SOFTWARE\\Martin Prikryl\\WinSCP 2\\Sessions"); // mostly from MSDN bool reg_get_list (string key, vector<string>& keylist, vector<string>& vallist) { HKEY hKey; TCHAR achKey[REG_MAXLEN_KEY]; // buffer for subkey name DWORD cbName; // size of name string TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name DWORD cchClassName = MAX_PATH; // size of class string DWORD cSubKeys=0; // number of subkeys DWORD cbMaxSubKey; // longest subkey size DWORD cchMaxClass; // longest class string DWORD cValues; // number of values for key DWORD cchMaxValue; // longest value name DWORD cbMaxValueData; // longest value data DWORD cbSecurityDescriptor; // size of security descriptor FILETIME ftLastWriteTime; // last write time DWORD i, retCode; TCHAR achValue[REG_MAXLEN_VAL]; DWORD cchValue = REG_MAXLEN_VAL; retCode = RegOpenKeyExA(HKEY_CURRENT_USER, key.c_str(), 0, KEY_READ, &hKey); if(retCode != ERROR_SUCCESS) { cout << "bark\n"; return false; } // Get the class name and the value count. retCode = RegQueryInfoKey( hKey, // key handle achClass, // buffer for class name &cchClassName, // size of class string NULL, // reserved &cSubKeys, // number of subkeys &cbMaxSubKey, // longest subkey size &cchMaxClass, // longest class string &cValues, // number of values for this key &cchMaxValue, // longest value name &cbMaxValueData, // longest value data &cbSecurityDescriptor, // security descriptor &ftLastWriteTime); // last write time if (cSubKeys) { // printf( "\nNumber of subkeys: %lu\n", cSubKeys); for (i=0; i<cSubKeys; i++) { cbName = REG_MAXLEN_KEY; retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime); if (retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achKey); keylist.push_back(achKey); } } } if (cValues) { // printf( "\nNumber of values: %lu\n", cValues); for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++) { cchValue = REG_MAXLEN_VAL; achValue[0] = '\0'; retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL); if(retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achValue); vallist.push_back(achValue); } } } RegCloseKey(hKey); return true; } bool reg_get_key (string location, string name, string& val) { HKEY key; TCHAR value[1024]; DWORD bufLen = 1024*sizeof(TCHAR); long ret; ret = RegOpenKeyExA(HKEY_CURRENT_USER, location.c_str(), 0, KEY_QUERY_VALUE, &key); if(ret != ERROR_SUCCESS) { return false; } ret = RegQueryValueExA(key, name.c_str(), 0, 0, (LPBYTE) value, &bufLen); RegCloseKey(key); if ( (ret != ERROR_SUCCESS) || (bufLen > 1024*sizeof(TCHAR)) ){ return false; } string stringValue = string(value, (size_t)bufLen - 1); size_t i = stringValue.length(); while( i > 0 && stringValue[i-1] == '\0' ){ --i; } val = stringValue; return true; } void decrypt_registry_session (string session) { const string kuser = TEXT("UserName"), khost = TEXT("HostName"), kpw = TEXT("Password"), ktunuser = TEXT("TunnelUserName"), ktunhost = TEXT("TunnelHostName"), ktunpw = TEXT("TunnelPassword"); bool r = true; string user, host, pw; string path = session_path + TEXT("\\") + session; // normal session r = r && reg_get_key(path, kuser, user); r = r && reg_get_key(path, khost, host); r = r && reg_get_key(path, kpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; // tunnel session r = r && reg_get_key(path, ktunuser, user); r = r && reg_get_key(path, ktunhost, host); r = r && reg_get_key(path, ktunpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; } void read_registry () { vector<string> keylist, vallist; bool r; r = reg_get_list(session_path, keylist, vallist); for(int i = 0; i < keylist.size(); i++) decrypt_registry_session(keylist[i]); } #endif int dec_next_char(string &s) { if(s.length() <= 0) return 0; const string base = "0123456789ABCDEF"; int a = base.find(s[0]); int b = base.find(s[1]); uchar r = (uchar) ~((a << 4) + (b << 0) ^ PW_MAGIC); s.erase(0, 2); return r; } string decrypt(string pwd, string key) { string clearpwd; uchar length, flag; flag = dec_next_char(pwd); if(flag == PW_FLAG) { dec_next_char(pwd); length = dec_next_char(pwd); } else length = flag; pwd.erase(0, (dec_next_char(pwd))*2); for(int i = 0; i < length; i++) clearpwd += (char)dec_next_char(pwd); if(flag == PW_FLAG) { if(clearpwd.substr(0, key.length()) != key) clearpwd = ""; else clearpwd.erase(0, key.length()); } return clearpwd; } string clean (string s) { int len = s.length(); if(len && s[len-1] == '\r') s.erase(len-1, 1); return s; } void parse_wscp_conf (char* path) { string l; string host, user, pwd; string tunnel_host, tunnel_user, tunnel_pwd; ifstream f(path); if(!f.is_open()) { cerr << "Cannot open " << path << "\n"; exit(1); } cerr << "reading " << path << "\n"; while(f.good()) { getline(f, l); if(l.substr(0, 9) == "UserName=") { user = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelUserName=") { tunnel_user = clean(l.substr(15)); } else if(l.substr(0, 9) == "HostName=") { host = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelHostName=") { tunnel_host = clean(l.substr(15)); } else if(l.substr(0, 9) == "Password=" || l.substr(0,15) == "TunnelPassword=") { int password_start = l.find_first_of('=') + 1; bool is_tunnel = password_start == 9; pwd = clean(l.substr(password_start)); if(is_tunnel && !user.empty() && !host.empty() && !pwd.empty()) { cout << user << "@" << host << "\t" << decrypt(pwd, user+host) << "\n"; } else if(!is_tunnel && !tunnel_user.empty() && !tunnel_host.empty()) { cout << tunnel_user << "@" << tunnel_host << "\t" << decrypt(pwd, tunnel_user+tunnel_host) << "\n"; } user = host = pwd = ""; } } f.close(); } int main (int argc, char** argv) { string user, host, pwd; switch(argc-1) { #ifdef WIN case 0: read_registry(); break; #endif case 1: if(string("-h") == argv[1] || string("/?") == argv[1]) goto help; parse_wscp_conf(argv[1]); break; case 3: user = argv[1]; host = argv[2]; pwd = argv[3]; cout << user << "@" << host << "\t" << decrypt(pwd, user+host); break; help: default: cerr << "Restore stored password from WinSCP.\n" << "Usage:\n\t" << argv[0] << " [user host cryptedpwd | path/to/winscp.ini | -h | /? ]\n" << "On Windows, no options means look up in the registry.\n" << "\nExamples:\n" << "\t" << argv[0] << " foo example.com A35C4E4502235B7335F65E12961302012888799B78BAF39F5A632CA6073A333339243D312C3039723F33313F3D3739B012F6\n" << "\t" << argv[0] << " /tmp/winscp.ini\n"; break; } return 0; } -
#include <string> #include <fstream> #include <iostream> #include <cstdlib> #include <vector> using namespace std; typedef unsigned char uchar; #define PW_MAGIC 0xA3 #define PW_MAXLEN 50 #define PW_FLAG 0xFF string decrypt(string pwd, string key); #ifdef WIN #include <windows.h> #define REG_MAXLEN_KEY 255 #define REG_MAXLEN_VAL 16383 const string session_path = TEXT("SOFTWARE\\Martin Prikryl\\WinSCP 2\\Sessions"); // mostly from MSDN bool reg_get_list (string key, vector<string>& keylist, vector<string>& vallist) { HKEY hKey; TCHAR achKey[REG_MAXLEN_KEY]; // buffer for subkey name DWORD cbName; // size of name string TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name DWORD cchClassName = MAX_PATH; // size of class string DWORD cSubKeys=0; // number of subkeys DWORD cbMaxSubKey; // longest subkey size DWORD cchMaxClass; // longest class string DWORD cValues; // number of values for key DWORD cchMaxValue; // longest value name DWORD cbMaxValueData; // longest value data DWORD cbSecurityDescriptor; // size of security descriptor FILETIME ftLastWriteTime; // last write time DWORD i, retCode; TCHAR achValue[REG_MAXLEN_VAL]; DWORD cchValue = REG_MAXLEN_VAL; retCode = RegOpenKeyExA(HKEY_CURRENT_USER, key.c_str(), 0, KEY_READ, &hKey); if(retCode != ERROR_SUCCESS) { cout << "bark\n"; return false; } // Get the class name and the value count. retCode = RegQueryInfoKey( hKey, // key handle achClass, // buffer for class name &cchClassName, // size of class string NULL, // reserved &cSubKeys, // number of subkeys &cbMaxSubKey, // longest subkey size &cchMaxClass, // longest class string &cValues, // number of values for this key &cchMaxValue, // longest value name &cbMaxValueData, // longest value data &cbSecurityDescriptor, // security descriptor &ftLastWriteTime); // last write time if (cSubKeys) { // printf( "\nNumber of subkeys: %lu\n", cSubKeys); for (i=0; i<cSubKeys; i++) { cbName = REG_MAXLEN_KEY; retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime); if (retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achKey); keylist.push_back(achKey); } } } if (cValues) { // printf( "\nNumber of values: %lu\n", cValues); for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++) { cchValue = REG_MAXLEN_VAL; achValue[0] = '\0'; retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL); if(retCode == ERROR_SUCCESS) { // printf("(%lu) %s\n", i+1, achValue); vallist.push_back(achValue); } } } RegCloseKey(hKey); return true; } bool reg_get_key (string location, string name, string& val) { HKEY key; TCHAR value[1024]; DWORD bufLen = 1024*sizeof(TCHAR); long ret; ret = RegOpenKeyExA(HKEY_CURRENT_USER, location.c_str(), 0, KEY_QUERY_VALUE, &key); if(ret != ERROR_SUCCESS) { return false; } ret = RegQueryValueExA(key, name.c_str(), 0, 0, (LPBYTE) value, &bufLen); RegCloseKey(key); if ( (ret != ERROR_SUCCESS) || (bufLen > 1024*sizeof(TCHAR)) ){ return false; } string stringValue = string(value, (size_t)bufLen - 1); size_t i = stringValue.length(); while( i > 0 && stringValue[i-1] == '\0' ){ --i; } val = stringValue; return true; } void decrypt_registry_session (string session) { const string kuser = TEXT("UserName"), khost = TEXT("HostName"), kpw = TEXT("Password"), ktunuser = TEXT("TunnelUserName"), ktunhost = TEXT("TunnelHostName"), ktunpw = TEXT("TunnelPassword"); bool r = true; string user, host, pw; string path = session_path + TEXT("\\") + session; // normal session r = r && reg_get_key(path, kuser, user); r = r && reg_get_key(path, khost, host); r = r && reg_get_key(path, kpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; // tunnel session r = r && reg_get_key(path, ktunuser, user); r = r && reg_get_key(path, ktunhost, host); r = r && reg_get_key(path, ktunpw, pw); if(r) cout << user << "@" << host << "\t" << decrypt(pw, user+host) << "\n"; } void read_registry () { vector<string> keylist, vallist; bool r; r = reg_get_list(session_path, keylist, vallist); for(int i = 0; i < keylist.size(); i++) decrypt_registry_session(keylist[i]); } #endif int dec_next_char(string &s) { if(s.length() <= 0) return 0; const string base = "0123456789ABCDEF"; int a = base.find(s[0]); int b = base.find(s[1]); uchar r = (uchar) ~((a << 4) + (b << 0) ^ PW_MAGIC); s.erase(0, 2); return r; } string decrypt(string pwd, string key) { string clearpwd; uchar length, flag; flag = dec_next_char(pwd); if(flag == PW_FLAG) { dec_next_char(pwd); length = dec_next_char(pwd); } else length = flag; pwd.erase(0, (dec_next_char(pwd))*2); for(int i = 0; i < length; i++) clearpwd += (char)dec_next_char(pwd); if(flag == PW_FLAG) { if(clearpwd.substr(0, key.length()) != key) clearpwd = ""; else clearpwd.erase(0, key.length()); } return clearpwd; } string clean (string s) { int len = s.length(); if(len && s[len-1] == '\r') s.erase(len-1, 1); return s; } void parse_wscp_conf (char* path) { string l; string host, user, pwd; string tunnel_host, tunnel_user, tunnel_pwd; ifstream f(path); if(!f.is_open()) { cerr << "Cannot open " << path << "\n"; exit(1); } cerr << "reading " << path << "\n"; while(f.good()) { getline(f, l); if(l.substr(0, 9) == "UserName=") { user = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelUserName=") { tunnel_user = clean(l.substr(15)); } else if(l.substr(0, 9) == "HostName=") { host = clean(l.substr(9)); } else if(l.substr(0, 15) == "TunnelHostName=") { tunnel_host = clean(l.substr(15)); } else if(l.substr(0, 9) == "Password=" || l.substr(0,15) == "TunnelPassword=") { int password_start = l.find_first_of('=') + 1; bool is_tunnel = password_start == 9; pwd = clean(l.substr(password_start)); if(is_tunnel && !user.empty() && !host.empty() && !pwd.empty()) { cout << user << "@" << host << "\t" << decrypt(pwd, user+host) << "\n"; } else if(!is_tunnel && !tunnel_user.empty() && !tunnel_host.empty()) { cout << tunnel_user << "@" << tunnel_host << "\t" << decrypt(pwd, tunnel_user+tunnel_host) << "\n"; } user = host = pwd = ""; } } f.close(); } int main (int argc, char** argv) { string user, host, pwd; switch(argc-1) { #ifdef WIN case 0: read_registry(); break; #endif case 1: if(string("-h") == argv[1] || string("/?") == argv[1]) goto help; parse_wscp_conf(argv[1]); break; case 3: user = argv[1]; host = argv[2]; pwd = argv[3]; cout << user << "@" << host << "\t" << decrypt(pwd, user+host); break; help: default: cerr << "Restore stored password from WinSCP.\n" << "Usage:\n\t" << argv[0] << " [user host cryptedpwd | path/to/winscp.ini | -h | /? ]\n" << "On Windows, no options means look up in the registry.\n" << "\nExamples:\n" << "\t" << argv[0] << " foo example.com A35C4E4502235B7335F65E12961302012888799B78BAF39F5A632CA6073A333339243D312C3039723F33313F3D3739B012F6\n" << "\t" << argv[0] << " /tmp/winscp.ini\n"; break; } return 0; }
-
WINDOWS XP CD KEYS: windows xp sp3 Serial No.V2C47-MK7JD-3R89F-D2KXW-VPK3J windows xp sp2 Serial No.YCKQV-CK63Y-2P3VG-8FTB6-T7W28 windows Professional Service Pack 3 Pro: Keys 1.FRH2X-6VD7F-YH2TV-2V8B7-J46F6 2.QKBGY-TBJFG-F448Q-24KR9-48XPJ 3.F9QV9-HDYR3-6QDR4-PGVW9-GTBBJ 4.H49F9-8RTVG-MTCVH-G2MFK-C47C8 Genuine xp pro key: 1.JG28K-H9Q7X-BH6W4-3PDCQ-6XBFJ Home Edition key:BQJG2-2MJT7-H7F6K-XW98B-4HQRQ windows xp professional sp2 key: VDDF2-JJWM3-X7P27-FRHRT-8BVHT windows xp unlimited uses code: BVK7Q-6PCMC-JCQ3B-C88MQ-P4J8J windows xp mix cd keys: 1.JD3T2-QH36R-X7W2W-7R3XT-DVRPQ 2.FC8GV-8Y7G7-XKD7P-Y47XF-P829W 3.CJ4BR-YHR9H-XPJB4-J4VWY-39XYW 4.H6TXY-698M6-BPF4K-32P94-CJX73 5.CGJ2M-CFTXY-W4RBJ-BWTGB-VH2CB 6.DFYXB-8FR68-FK2DX-Y2RDR-M4C6M XP Service Pack 3 V2C47-MK7JD-3R89F-D2KXW-VPK3J