mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
+Draw/, Report/, PdfDraw/, DocTypes/: minimalistic PDF/A support
+plugin/wincert: basic Win32 certificate manipulation and PDF digital signing git-svn-id: svn://ultimatepp.org/upp/trunk@3715 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
80abeb8192
commit
9ab49c4b9f
13 changed files with 777 additions and 29 deletions
|
|
@ -111,7 +111,7 @@ public:
|
|||
virtual ~DocReport();
|
||||
};
|
||||
|
||||
String Pdf(const DocReport& report);
|
||||
String Pdf(const DocReport& report, bool pdfa = false);
|
||||
|
||||
class ReportCtrl : public Ctrl {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -172,10 +172,10 @@ ReportDlg::ReportDlg()
|
|||
pdf <<= THISBACK(Pdf);
|
||||
}
|
||||
|
||||
String Pdf(const DocReport& report)
|
||||
String Pdf(const DocReport& report, bool pdfa)
|
||||
{
|
||||
return GetDrawingToPdfFn() ? (*GetDrawingToPdfFn())(report.GetPages(), report.GetPageSize(),
|
||||
200)
|
||||
200, pdfa)
|
||||
: String();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -865,7 +865,7 @@ void DrawTLText(Draw& draw, int x, int y, int cx, const wchar *text, Font font =
|
|||
Color ink = SColorText(), int accesskey = 0);
|
||||
|
||||
|
||||
typedef String (*DrawingToPdfFnType)(const Array<Drawing>& report, Size pagesize, int margin);
|
||||
typedef String (*DrawingToPdfFnType)(const Array<Drawing>& report, Size pagesize, int margin, bool pdfa);
|
||||
|
||||
void SetDrawingToPdfFn(DrawingToPdfFnType Pdf);
|
||||
DrawingToPdfFnType GetDrawingToPdfFn();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,100 @@ NAMESPACE_UPP
|
|||
#define PDF_COMPRESS
|
||||
#define USE_TTF
|
||||
|
||||
static const char ICC_ColorSpaceInfo[] =
|
||||
"H\211\234\226yTSw\026\307\177o\311\236\220\225\260\303c\r[\200\260\006\2205la\221"
|
||||
"\035\004Q\bI\b\001\022BH\330\005AD\005\024ED\204\252\2252\326mtFOE\235.\256c\255\016"
|
||||
"\326}\352\322\003\3650\352\3508\264\026\327\216\235\0278G\235Ng\246\323\357\037\357"
|
||||
"\3679\367w\357\357\335\337\275\367\235\363\000\240'\245\252\265\3250\v\000\215\326"
|
||||
"\240\317J\214\305\026\025\024b\244\t\000\003\n \002\021\0002y\255.-;!\a\340\222\306"
|
||||
"K\260Z\334\t\374\213\236^\a\220i\275\"L\312\3000\360\377\211-\327\351\r\000@\0318"
|
||||
"\a(\224\265r\234;q\256\2527\350L\366\031\234y\245\225&\206Q\023\353\361\004q\2664"
|
||||
"\261j\236\275\347|\3469\332\304\n\215V\201\263)g\235B\2430\361i\234W\327\031\2258"
|
||||
"#\2518w\325\251\225\3658_\305\331\245\312\250Q\343\374\334\024\253Q\312j\001@\351"
|
||||
"&\273A)/\307\331\017g\272>'K\202\363\002\000\310t\325;\\\372\016\033\224\r\006\323"
|
||||
"\245$\325\272F\275ZUn\300\334\345\036\230(4T\214%)\353\253\224\006\2030C&\257\224"
|
||||
"\351\025\230\244Z\243\223i\033\001\230\277\363\2348\246\332bx\221\203E\241\301\301"
|
||||
"B\177\037\321;\205\372\257\233\277P\246\336\316\323\223\314\271\236A\374\vom?\347"
|
||||
"W=\n\200x\026\257\315\372\267\266\322-\000\214\257\004\300\362\346[\233\313\373\000"
|
||||
"0\361\276\035\276\370\316}\370\246y)7\030ta\276\276\365\365\365>j\245\334\307T\320"
|
||||
"7\372\237\016\277@\357\274\317\307t\334\233\362`q\3122\231\261\312\200\231\352&\257"
|
||||
"\256\2526\352\261Z\235L\256\304\204?\035\342_\035\370\363yxg)\313\224z\245\026\217"
|
||||
"\310\303\247L\255U\341\355\326*\324\006u\265\026Sk\377S\023\177e\330O4?\327\270\270"
|
||||
"c\257\001\257\330\a\260.\362\000\362\267\v\000\345\322\000R\264\r\337\201\336\364"
|
||||
"-\225\222\a2\3605\337\341\336\374\334\317\t\372\367S\341>\323\243V\255\232\213\223"
|
||||
"d\345`r\243\276n~\317\364Y\002\002\240\002&\340\001+`\017\234\201;\020\002\177\020"
|
||||
"\002\302A4\210\a\311 \035\344\200\002\260\024\310A9\320\000=\250\a-\240\035t\201\036"
|
||||
"\260\036l\002\303`;\030\003\273\301~p\020\214\203\217\301\t\360Gp\036|\t\256\201["
|
||||
"`\022L\203\207`\006<\005\257 \b\"A\f\210\vYA\016\220+\344\005\371Cb(\022\212\207R"
|
||||
"\241,\250\000*\201T\220\0262B-\320\n\250\a\352\207\206\241\035\320n\350\367\320Q\350"
|
||||
"\004t\016\272\004}\005MA\017\240\357\240\2270\002\323a\036l\a\273\301\276\260\030"
|
||||
"\216\201S\340\034x\t\254\202k\340&\270\023^\a\017\301\243\360>\3700|\002>\017_\203"
|
||||
"'\341\207\360,\002\020\032\302G\034\021!\"F$H:R\210\224!z\244\025\351F\006\221Qd?"
|
||||
"r\f9\213\\A&\221G\310\v\224\210rQ\f\025\242\341h\022\232\213\312\321\032\264\025\355"
|
||||
"E\207\321]\350a\3644z\005\235Bg\320\327\004\006\301\226\340E\b#H\t\213\b*B=\241\213"
|
||||
"0H\330I\370\210p\206p\2150MxJ$\022\371D\0011\204\230D, V\020\233\211\275\304\255\304"
|
||||
"\003\304\343\304K\304\273\304Y\022\211dE\362\"E\220\322I2\222\201\324E\332B\332G\372"
|
||||
"\214t\2314MzN\246\221\035\310\376\344\004r!YK\356 \017\222\367\220?%_&\337#\277\242"
|
||||
"\260(\256\2240J:EAi\244\364Q\306(\307(\027)\323\224WT6U@\215\240\346P+\250\355\324"
|
||||
"!\352~\352\031\352m\352\023\032\215\346D\v\245e\322\324\264\345\264!\332\357h\237"
|
||||
"\323\246h/\350\034\272']B/\242\033\351\353\350\037\322\217\323\277\242?a0\030n\214"
|
||||
"hF!\303\300X\307\330\3158\305\370\232\361\334\214k\346c&5S\230\265\231\215\230\035"
|
||||
"6\273l\366\230Ia\2722c\230K\231M\314A\346!\346E\346#\026\205\345\306\222\260d\254"
|
||||
"V\326\b\353(\353\006k\226\315e\213\330\351l\r\273\227\275\207}\216}\237C\342\270q"
|
||||
"\3429\nN'\347\003\316)\316].\302u\346J\270r\356\n\356\030\367\fw\232G\344\txR^\005"
|
||||
"\257\207\367[\336\004o\306\234c\036h\236g\336`>b\376\211\371$\037\341\273\361\245"
|
||||
"\374*~\037\377 \377:\377\245\205\235E\214\205\322b\215\305~\213\313\026\317,m,\243"
|
||||
"-\225\226\335\226\a,\257Y\276\264\302\254\342\255*\2556X\215[\335\261F\255=\2553\255"
|
||||
"\353\255\267Y\237\261~d\303\263\t\267\221\333t\333\034\264\271i\v\333z\332f\3316\333"
|
||||
"~`{\301v\326\316\336.\321Ng\267\305\356\224\335#{\276}\264}\205\375\200\375\247\366"
|
||||
"\017\034\270\016\221\016j\207\001\207\317\034\376\212\231c1X\0256\204\235\306f\034"
|
||||
"m\035\223\034\215\216;\034'\034_9\t\234r\235:\234\0168\335q\246:\213\235\313\234\a"
|
||||
"\234O:\317\2708\270\244\271\264\270\354u\271\351Jq\025\273\226\273nv=\353\372\314"
|
||||
"M\340\226\357\266\312m\334\355\276\300R \0254\t\366\nn\2733\334\243\334k\334G\335"
|
||||
"\257z\020=\304\036\225\036[=\276\364\204=\203<\313=G</z\301^\301^j\257\255^\227\274"
|
||||
"\t\336\241\336Z\357Q\357\033B\2720FX'\334+\234\362\341\373\244\372t\370\214\373<\366"
|
||||
"u\361-\364\335\340{\326\367\265_\220_\225\337\230\337-\021G\224,\352\020\035\023}"
|
||||
"\347\357\351/\367\037\361\277\032\300\bH\bh\v8\022\360m\240W\2402p[\340\237\203\270"
|
||||
"AiA\253\202N\006\375#8$X\037\274?\370A\210KHI\310{!7\304<q\206\270W\374y(!46\264-"
|
||||
"\364\343\320\027a\301a\206\260\203a\177\017\027\206W\206\357\t\277\277@\260@\271`"
|
||||
"l\301\335\b\247\bY\304\216\210\311H,\262$\362\375\310\311(\307(Y\324h\3247\321\316"
|
||||
"\321\212\350\235\321\367b<b*b\366\305<\216\365\213\325\307~\024\373L\022&Y&9\036\207"
|
||||
"\304%\306u\307M\304s\342s\343\207\343\277NpJP%\354M\230I\fJlN<\236DHJI\332\220tCj"
|
||||
"'\225KwKg\222C\222\227%\237N\241\247d\247\f\247|\223\352\231\252O=\226\006\247%\247"
|
||||
"mL\273\275\320u\241v\341x:H\227\246oL\277\223!\310\250\311\370C&13#s$\363/Y\242\254"
|
||||
"\226\254\263\331\334\354\342\354=\331Osbs\372rn\345\272\347\032sO\3461\363\212\362"
|
||||
"v\347=\313\217\313\357\317\237\\\344\273h\331\242\363\005\326\005\352\202#\205\244"
|
||||
"\302\274\302\235\205\263\213\343\027oZ<]\024T\324Ut}\211`I\303\222sK\255\227V-\375"
|
||||
"\244\230Y,+>TB(\311/\331S\362\203,]6*\233-\225\226\276W:#\227\3107\313\037*\242\025"
|
||||
"\003\212\a\312\be\277\362^YDY\177\331}U\204j\243\352AyT\371`\371#\265D=\254\376\266"
|
||||
"\"\251b{\305\263\312\364\312\017+\177\254\312\257:\240!kJ4G\265\034m\245\366t\265"
|
||||
"}uC\365%\235\227\256K7Y\023V\263\251fF\237\242\337Y\v\325.\251=b\340\341?S\027\214"
|
||||
"\356\306\225\306\251\272\310\272\221\272\347\365y\365\207\032\330\r\332\206\v\215"
|
||||
"\236\215k\032\3575%4\375\246\031m\2267\237lqlio\231Z\026\263lG+\324Z\332z\262\315"
|
||||
"\271\255\263mzy\342\362]\355\324\366\312\366?u\370u\364w|\277\"\177\305\261N\273\316"
|
||||
"\345\235wW&\256\334\333e\326\245\357\272\261*|\325\366\325\350j\365\352\2115\001k"
|
||||
"\266\254y\335\255\350\376\242\307\257g\260\347\207^y\357\027kEk\207\326\376\270\256"
|
||||
"l\335D_p\337\266\365\304\365\332\365\3277Dm\330\325\317\356o\352\277\2731m\343\341"
|
||||
"\001l\240{\340\373M\305\233\316\r\006\016n\337L\335l\334<9\224\372O\000\244\001[\376"
|
||||
"\230\270\231$\231\220\231\374\232h\232\325\233B\233\257\234\034\234\211\234\367\235"
|
||||
"d\235\322\236@\236\256\237\035\237\213\237\372\240i\240\330\241G\241\266\242&\242"
|
||||
"\226\243\006\243v\243\346\244V\244\307\2458\245\251\246\032\246\213\246\375\247n\247"
|
||||
"\340\250R\250\304\2517\251\251\252\034\252\217\253\002\253u\253\351\254\\\254\320"
|
||||
"\255D\255\270\256-\256\241\257\026\257\213\260\000\260u\260\352\261`\261\326\262K"
|
||||
"\262\302\2638\263\256\264%\264\234\265\023\265\212\266\001\266y\266\360\267h\267\340"
|
||||
"\270Y\270\321\271J\271\302\272;\272\265\273.\273\247\274!\274\233\275\025\275\217"
|
||||
"\276\n\276\204\276\377\277z\277\365\300p\300\354\301g\301\343\302_\302\333\303X\303"
|
||||
"\324\304Q\304\316\305K\305\310\306F\306\303\307A\307\277\310=\310\274\311:\311\271"
|
||||
"\3128\312\267\3136\313\266\3145\314\265\3155\315\265\3166\316\266\3177\317\270\320"
|
||||
"9\320\272\321<\321\276\322?\322\301\323D\323\306\324I\324\313\325N\325\321\326U\326"
|
||||
"\330\327\\\327\340\330d\330\350\331l\331\361\332v\332\373\333\200\334\005\334\212"
|
||||
"\335\020\335\226\336\034\336\242\337)\337\257\3406\340\275\341D\341\314\342S\342\333"
|
||||
"\343c\343\353\344s\344\374\345\204\346\r\346\226\347\037\347\251\3502\350\274\351"
|
||||
"F\351\320\352[\352\345\353p\353\373\354\206\355\021\355\234\356(\356\264\357@\357"
|
||||
"\314\360X\360\345\361r\361\377\362\214\363\031\363\247\3644\364\302\365P\365\336\366"
|
||||
"m\366\373\367\212\370\031\370\250\3718\371\307\372W\372\347\373w\374\a\374\230\375"
|
||||
")\375\272\376K\376\334\377m\377\377\002\f\000\367\204\363\373";
|
||||
|
||||
dword PdfDraw::GetInfo() const
|
||||
{
|
||||
return DOTS;
|
||||
|
|
@ -18,10 +112,11 @@ Size PdfDraw::GetPageSize() const
|
|||
return pgsz;
|
||||
}
|
||||
|
||||
void PdfDraw::Init(int pagecx, int pagecy, int _margin)
|
||||
void PdfDraw::Init(int pagecx, int pagecy, int _margin, bool _pdfa)
|
||||
{
|
||||
Clear();
|
||||
margin = _margin;
|
||||
pdfa = _pdfa;
|
||||
pgsz.cx = pagecx;
|
||||
pgsz.cy = pagecy;
|
||||
pgsz += margin;
|
||||
|
|
@ -55,20 +150,22 @@ void PdfDraw::PutRect(const Rect& rc)
|
|||
<< Pt(rc.Width()) << ' ' << Pt(rc.Height()) << " re\n";
|
||||
}
|
||||
|
||||
int PdfDraw::PutStream(const String& data, const String& keys)
|
||||
int PdfDraw::PutStream(const String& data, const String& keys, bool compress)
|
||||
{
|
||||
#ifdef PDF_COMPRESS
|
||||
String c = ZCompress(data);
|
||||
if(c.GetLength() < data.GetLength()) {
|
||||
BeginObj();
|
||||
out << "<< " << keys
|
||||
<< "/Length " << c.GetLength() << " "
|
||||
<< "/Length1 " << data.GetLength() << " "
|
||||
<< "/Filter /FlateDecode "
|
||||
<< " >>\n"
|
||||
<< "stream\r\n" << c << "\r\nendstream\n";
|
||||
EndObj();
|
||||
return offset.GetCount();
|
||||
if(compress) {
|
||||
String c = ZCompress(data);
|
||||
if(c.GetLength() < data.GetLength()) {
|
||||
BeginObj();
|
||||
out << "<< " << keys
|
||||
<< "/Length " << c.GetLength() << " "
|
||||
<< "/Length1 " << data.GetLength() << " "
|
||||
<< "/Filter /FlateDecode "
|
||||
<< " >>\n"
|
||||
<< "stream\r\n" << c << "\r\nendstream\n";
|
||||
EndObj();
|
||||
return offset.GetCount();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
BeginObj();
|
||||
|
|
@ -669,7 +766,7 @@ String PdfDraw::Finish()
|
|||
}
|
||||
}
|
||||
imgobj << "/Type /XObject /Subtype /Image" << wh
|
||||
<< " /BitsPerComponent 8 /ColorSpace /DeviceRGB";
|
||||
<< " /BitsPerComponent 8 /ColorSpace /DeviceRGB /Intent /Perceptual";
|
||||
}
|
||||
}
|
||||
if(mask >= 0)
|
||||
|
|
@ -965,6 +1062,21 @@ String PdfDraw::Finish()
|
|||
out << ">>\n";
|
||||
EndObj();
|
||||
|
||||
int dflt_rgb_def = -1;
|
||||
if(pdfa) {
|
||||
int icc_info = BeginObj();
|
||||
static const int data_len = __countof(ICC_ColorSpaceInfo) - 1;
|
||||
out << "<</Length " << data_len << "/Filter/FlateDecode/N 3>>\n"
|
||||
"stream\n";
|
||||
out.Cat(ICC_ColorSpaceInfo, data_len);
|
||||
out << "\nendstream\n";
|
||||
EndObj();
|
||||
|
||||
dflt_rgb_def = BeginObj();
|
||||
out << "[/ICCBased " << icc_info << " 0 R]\n";
|
||||
EndObj();
|
||||
}
|
||||
|
||||
int resources = BeginObj();
|
||||
out << "<< /Font " << fonts << " 0 R\n"
|
||||
"/ProcSet [ /PDF /Text /ImageB /ImageC ]\n";
|
||||
|
|
@ -982,6 +1094,9 @@ String PdfDraw::Finish()
|
|||
out << "/Pat" << (i + 1) << ' ' << patternobj[i] << " 0 R ";
|
||||
out << ">>\n";
|
||||
}
|
||||
if(pdfa) {
|
||||
out << "/ColorSpace <</DefaultRGB " << dflt_rgb_def << " 0 R>>\n";
|
||||
}
|
||||
out << ">>\n";
|
||||
EndObj();
|
||||
|
||||
|
|
@ -1009,11 +1124,66 @@ String PdfDraw::Finish()
|
|||
"/Count 0\n"
|
||||
">>\n";
|
||||
EndObj();
|
||||
int pdfa_metadata = -1;
|
||||
if(pdfa) {
|
||||
StringBuffer metadata;
|
||||
metadata <<
|
||||
"<?xpacket id=\"" << Uuid::Create() << "\"?>\n"
|
||||
"<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"PDFNet\">\n"
|
||||
"<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
|
||||
"<rdf:Description rdf:about=\"\"\n"
|
||||
"xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n"
|
||||
"<xmp:CreateDate>0000-01-01</xmp:CreateDate>\n"
|
||||
"<xmp:ModifyDate>0000-01-01</xmp:ModifyDate>\n"
|
||||
"<xmp:CreatorTool/>\n"
|
||||
"</rdf:Description>\n"
|
||||
"<rdf:Description rdf:about=\"\"\n"
|
||||
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"
|
||||
"<dc:title>\n"
|
||||
"<rdf:Alt>\n"
|
||||
"<rdf:li xml:lang=\"x-default\"/>\n"
|
||||
"</rdf:Alt>\n"
|
||||
"</dc:title>\n"
|
||||
"<dc:creator>\n"
|
||||
"<rdf:Seq>\n"
|
||||
"<rdf:li/>\n"
|
||||
"</rdf:Seq>\n"
|
||||
"</dc:creator>\n"
|
||||
"<dc:description>\n"
|
||||
"<rdf:Alt>\n"
|
||||
"<rdf:li xml:lang=\"x-default\"/>\n"
|
||||
"</rdf:Alt>\n"
|
||||
"</dc:description>\n"
|
||||
"</rdf:Description>\n"
|
||||
"<rdf:Description rdf:about=\"\"\n"
|
||||
"xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n"
|
||||
"<pdf:Keywords/>\n"
|
||||
"<pdf:Producer/>\n"
|
||||
"</rdf:Description>\n"
|
||||
"<rdf:Description rdf:about=\"\"\n"
|
||||
"xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n"
|
||||
"<pdfaid:part>1</pdfaid:part>\n"
|
||||
"<pdfaid:conformance>B</pdfaid:conformance>\n"
|
||||
"</rdf:Description>\n"
|
||||
"</rdf:RDF>\n"
|
||||
"</x:xmpmeta>\n";
|
||||
|
||||
StringBuffer meta_head;
|
||||
meta_head << "/Type/Metadata/Subtype/XML";
|
||||
|
||||
pdfa_metadata = PutStream(metadata, meta_head, false);
|
||||
}
|
||||
|
||||
int catalog = BeginObj();
|
||||
out << "<< /Type /Catalog\n"
|
||||
<< "/Outlines " << outlines << " 0 R\n"
|
||||
<< "/Pages " << pages << " 0 R\n"
|
||||
<< ">>\n";
|
||||
<< "/Pages " << pages << " 0 R\n";
|
||||
|
||||
if(pdfa_metadata >= 0) {
|
||||
out << "/Metadata " << pdfa_metadata << " 0 R\n";
|
||||
}
|
||||
|
||||
out << ">>\n";
|
||||
EndObj();
|
||||
int startxref = out.GetCount();
|
||||
out << "xref\n"
|
||||
|
|
|
|||
|
|
@ -284,13 +284,14 @@ private:
|
|||
double linewidth;
|
||||
int margin;
|
||||
uint64 patternid;
|
||||
bool pdfa;
|
||||
|
||||
inline double Pt(double dot) { return 0.12 * dot; }
|
||||
|
||||
int Pos() { return offset.GetCount() + 1; }
|
||||
int BeginObj();
|
||||
void EndObj();
|
||||
int PutStream(const String& data, const String& keys = Null);
|
||||
int PutStream(const String& data, const String& keys = Null, bool compress = true);
|
||||
|
||||
void PutRect(const Rect& rc);
|
||||
void PutrgColor(Color rg, uint64 pattern = 0);
|
||||
|
|
@ -320,7 +321,7 @@ private:
|
|||
M22() : a(1), b(0), c(0), d(1) {}
|
||||
};
|
||||
|
||||
void Init(int pagecx, int pagecy, int margin);
|
||||
void Init(int pagecx, int pagecy, int margin, bool pdfa);
|
||||
|
||||
struct RGlyph : Moveable<RGlyph> {
|
||||
String data;
|
||||
|
|
@ -334,8 +335,8 @@ public:
|
|||
String Finish();
|
||||
void Clear();
|
||||
|
||||
PdfDraw(int pagecx, int pagecy) { Init(pagecx, pagecy, 0); }
|
||||
PdfDraw(Size pgsz = Size(5100, 6600)) { Init(pgsz.cx, pgsz.cy, 0); }
|
||||
PdfDraw(int pagecx, int pagecy, bool pdfa = false) { Init(pagecx, pagecy, 0, pdfa); }
|
||||
PdfDraw(Size pgsz = Size(5100, 6600), bool pdfa = false) { Init(pgsz.cx, pgsz.cy, 0, pdfa); }
|
||||
};
|
||||
|
||||
String Pdf(const Array<Drawing>& report, Size pagesize, int margin);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
NAMESPACE_UPP
|
||||
|
||||
String Pdf(const Array<Drawing>& report, Size sz, int margin)
|
||||
String Pdf(const Array<Drawing>& report, Size sz, int margin, bool pdfa)
|
||||
{
|
||||
PdfDraw w(sz + 2 * margin);
|
||||
PdfDraw w(sz + 2 * margin, pdfa);
|
||||
for(int i = 0; i < report.GetCount(); i++) {
|
||||
w.StartPage();
|
||||
w.DrawDrawing(margin, margin, sz.cx, sz.cy, report[i]);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ public:
|
|||
ReportWindow();
|
||||
};
|
||||
|
||||
String Pdf(Report& report);
|
||||
String Pdf(Report& report, bool pdfa = false);
|
||||
void Print(Report& r, PrinterJob& pd, bool center = true);
|
||||
bool DefaultPrint(Report& r, int i, const char *_name = t_("Report"));
|
||||
bool Print(Report& r, int i, const char *name = t_("Report"));
|
||||
|
|
|
|||
|
|
@ -214,10 +214,10 @@ ReportWindow::ReportWindow()
|
|||
pdf <<= THISBACK(Pdf);
|
||||
}
|
||||
|
||||
String Pdf(Report& report)
|
||||
String Pdf(Report& report, bool pdfa)
|
||||
{
|
||||
return GetDrawingToPdfFn() && report.GetCount() ?
|
||||
(*GetDrawingToPdfFn())(report.GetPages(), report.GetPage(0).GetSize(), 200)
|
||||
(*GetDrawingToPdfFn())(report.GetPages(), report.GetPage(0).GetSize(), 200, pdfa)
|
||||
: String();
|
||||
}
|
||||
|
||||
|
|
|
|||
4
uppsrc/plugin/wincert/init
Normal file
4
uppsrc/plugin/wincert/init
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef _plugin_wincert_icpp_init_stub
|
||||
#define _plugin_wincert_icpp_init_stub
|
||||
#include "Web/init"
|
||||
#endif
|
||||
363
uppsrc/plugin/wincert/pdf.cpp
Normal file
363
uppsrc/plugin/wincert/pdf.cpp
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
#include "wincert.h"
|
||||
|
||||
class PDFInfo {
|
||||
public:
|
||||
struct Reference : Moveable<Reference> {
|
||||
Reference(const Nuller& = Null) : index(0) {}
|
||||
Reference(int index_, word revision_) : index(index_), revision(revision_) {}
|
||||
|
||||
String ToString() const;
|
||||
|
||||
bool IsNullInstance() const { return index == 0; }
|
||||
|
||||
int index;
|
||||
word revision;
|
||||
};
|
||||
|
||||
PDFInfo();
|
||||
|
||||
void Clear();
|
||||
|
||||
bool Open(const String& pdf_data);
|
||||
|
||||
public:
|
||||
bool SkipWhite();
|
||||
bool Check(const char *text);
|
||||
int ScanInteger();
|
||||
Reference ScanReference();
|
||||
|
||||
bool ParseXRef(int startxref);
|
||||
bool ParseRoot();
|
||||
bool ParsePageTree(Reference root);
|
||||
|
||||
bool Seek(Reference ref);
|
||||
|
||||
public:
|
||||
enum { MAX_PDF_OBJECTS = 1000000 };
|
||||
|
||||
String pdf_data;
|
||||
Vector<int> objects;
|
||||
Vector<word> revisions;
|
||||
Vector<Reference> pages;
|
||||
int startxref;
|
||||
Reference trailer_root;
|
||||
Reference trailer_info;
|
||||
Reference page_tree;
|
||||
String root_object;
|
||||
const char *term;
|
||||
};
|
||||
|
||||
String PDFInfo::Reference::ToString() const
|
||||
{
|
||||
StringBuffer out;
|
||||
out << index << ' ' << (int)revision << " R";
|
||||
return out;
|
||||
}
|
||||
|
||||
PDFInfo::PDFInfo()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void PDFInfo::Clear()
|
||||
{
|
||||
pdf_data = Null;
|
||||
objects.Clear();
|
||||
revisions.Clear();
|
||||
startxref = -1;
|
||||
trailer_root = Null;
|
||||
trailer_info = Null;
|
||||
page_tree = Null;
|
||||
root_object = Null;
|
||||
term = NULL;
|
||||
}
|
||||
|
||||
bool PDFInfo::Open(const String& pdf_data_)
|
||||
{
|
||||
Clear();
|
||||
pdf_data = pdf_data_;
|
||||
const char *begin = pdf_data.Begin();
|
||||
term = pdf_data.End();
|
||||
while(term > begin && (byte)term[-1] <= ' ')
|
||||
term--;
|
||||
if(term - begin <= 5 || memcmp(term - 5, "%%EOF", 5))
|
||||
return false;
|
||||
term -= 5;
|
||||
while(term > begin && !IsDigit(*--term))
|
||||
;
|
||||
while(term > begin && IsDigit(term[-1]))
|
||||
term--;
|
||||
startxref = ScanInt(term);
|
||||
if(!ParseXRef(startxref))
|
||||
return false;
|
||||
if(!ParseRoot() || !ParsePageTree(page_tree))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PDFInfo::ParseXRef(int start)
|
||||
{
|
||||
if(start < 0 || start >= pdf_data.GetLength() - 20)
|
||||
return false;
|
||||
term = pdf_data.GetIter(start);
|
||||
if(!Check("xref"))
|
||||
return false;
|
||||
while(!Check("trailer")) {
|
||||
if(!SkipWhite())
|
||||
return false;
|
||||
int start = ScanInteger();
|
||||
int count = ScanInteger();
|
||||
if(start < 0 || count <= 0 || start + count > MAX_PDF_OBJECTS || !SkipWhite())
|
||||
return false;
|
||||
int end = start + count;
|
||||
if(objects.GetCount() < end) {
|
||||
objects.SetCountR(end, -1);
|
||||
revisions.SetCountR(end, 0xffffu);
|
||||
}
|
||||
for(int i = 0; i < count; i++) {
|
||||
int offset = ScanInteger();
|
||||
int rev = ScanInteger();
|
||||
if(!SkipWhite())
|
||||
return false;
|
||||
if(*term != 'f' && *term != 'n')
|
||||
return false;
|
||||
if(*term++ == 'f') {
|
||||
offset = 0;
|
||||
rev = 0xffffu;
|
||||
}
|
||||
if(objects[start + i] == -1) {
|
||||
objects[start + i] = offset;
|
||||
revisions[start + i] = rev;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!Check("<<"))
|
||||
return false;
|
||||
while(!Check(">>")) {
|
||||
if(!SkipWhite())
|
||||
return false;
|
||||
if(Check("/Size")) {
|
||||
int sz = ScanInteger();
|
||||
if(sz < objects.GetCount())
|
||||
return false;
|
||||
objects.SetCount(sz, -1);
|
||||
revisions.SetCount(sz, 0xffffu);
|
||||
}
|
||||
else if(Check("/Root")) {
|
||||
Reference root = ScanReference();
|
||||
if(IsNull(trailer_root))
|
||||
trailer_root = root;
|
||||
}
|
||||
else if(Check("/Info")) {
|
||||
Reference info = ScanReference();
|
||||
if(IsNull(trailer_info))
|
||||
trailer_info = info;
|
||||
}
|
||||
else if(Check("/Prev")) {
|
||||
int prev = ScanInteger();
|
||||
const char *store_term = term;
|
||||
if(!ParseXRef(prev))
|
||||
return false;
|
||||
term = store_term;
|
||||
}
|
||||
else {
|
||||
while(*++term && *term != '/' && !(*term == '>' && term[1] == '>'))
|
||||
;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PDFInfo::Seek(Reference r)
|
||||
{
|
||||
if(r.index <= 0 || r.index >= objects.GetCount() || objects[r.index] == -1)
|
||||
return false;
|
||||
term = pdf_data.GetIter(objects[r.index]);
|
||||
int index = ScanInteger();
|
||||
if(index != r.index)
|
||||
return false;
|
||||
int rev = ScanInteger();
|
||||
if(rev != r.revision)
|
||||
return false;
|
||||
if(!Check("obj") || !Check("<<"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PDFInfo::ParseRoot()
|
||||
{
|
||||
if(!Seek(trailer_root))
|
||||
return false;
|
||||
const char *begin = term;
|
||||
while(*term) {
|
||||
if(Check("/Pages")) {
|
||||
page_tree = ScanReference();
|
||||
}
|
||||
else
|
||||
if(*term == '>' && term[1] == '>')
|
||||
break;
|
||||
else
|
||||
term++;
|
||||
}
|
||||
root_object = String(begin, term);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PDFInfo::ParsePageTree(Reference node)
|
||||
{
|
||||
if(!Seek(node))
|
||||
return false;
|
||||
if(!Check("/Type"))
|
||||
return false;
|
||||
if(Check("/Pages")) {
|
||||
if(!Check("/Kids") || !Check("["))
|
||||
return false;
|
||||
while(*term && !Check("]")) {
|
||||
Reference kid = ScanReference();
|
||||
const char *stack = term;
|
||||
if(!ParsePageTree(kid))
|
||||
return false;
|
||||
term = stack;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(Check("/Page")) {
|
||||
pages.Add(node);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PDFInfo::SkipWhite()
|
||||
{
|
||||
while(*term && (byte)*term <= ' ')
|
||||
term++;
|
||||
return !!*term;
|
||||
}
|
||||
|
||||
bool PDFInfo::Check(const char *text)
|
||||
{
|
||||
if(!SkipWhite())
|
||||
return false;
|
||||
int l = strlen(text);
|
||||
if(memcmp(term, text, l))
|
||||
return false;
|
||||
term += l;
|
||||
return true;
|
||||
}
|
||||
|
||||
int PDFInfo::ScanInteger()
|
||||
{
|
||||
if(!SkipWhite())
|
||||
return Null;
|
||||
return ScanInt(term, &term);
|
||||
}
|
||||
|
||||
PDFInfo::Reference PDFInfo::ScanReference()
|
||||
{
|
||||
int obj = ScanInteger();
|
||||
if(IsNull(obj))
|
||||
return Reference();
|
||||
int rev = ScanInteger();
|
||||
if(IsNull(rev))
|
||||
return Reference();
|
||||
if(SkipWhite() && *term == 'R') {
|
||||
term++;
|
||||
return Reference(obj, rev);
|
||||
}
|
||||
return Reference();
|
||||
}
|
||||
|
||||
String CertSignPDF(PCCERT_CONTEXT cert_context, const String& pdf_data)
|
||||
{
|
||||
PDFInfo pdfinfo;
|
||||
if(!pdfinfo.Open(pdf_data) || pdfinfo.pages.IsEmpty())
|
||||
return String::GetVoid();
|
||||
StringBuffer out;
|
||||
out.Cat(pdf_data);
|
||||
int obj_index = pdfinfo.objects.GetCount();
|
||||
int sign_object = obj_index++;
|
||||
int sign_dict = obj_index++;
|
||||
int new_root = obj_index++;
|
||||
int sign_off = out.GetLength();
|
||||
out << sign_object << " 0 obj\n"
|
||||
"<</FT/Sig/T(Signature1)"
|
||||
"/V " << sign_dict << " 0 R"
|
||||
"/F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]";
|
||||
if(!IsNull(pdfinfo.page_tree))
|
||||
out << "/P " << pdfinfo.pages[0];
|
||||
out << ">>\n"
|
||||
"endobj\n";
|
||||
int dict_off = out.GetLength();
|
||||
Time tm = GetSysTime();
|
||||
out << sign_dict << " 0 obj\n"
|
||||
"<</Type/Sig/Filter/Adobe.PPKLite/SubFilter/adbe.pkcs7.detached"
|
||||
"/Reason()"
|
||||
"/Location()"
|
||||
"/ContactInfo()"
|
||||
"/M(D:" << NFormat("%04d%02d%02d%02d%02d%02d+02'00'",
|
||||
tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second)
|
||||
<< ")/ByteRange [0 ";
|
||||
int br_offset = out.GetLength();
|
||||
int cert_length = 4096;
|
||||
String tail = "/Contents <";
|
||||
static const int RCL_CONT = 60;
|
||||
for(;;) {
|
||||
out.SetLength(br_offset);
|
||||
out.Cat(' ', RCL_CONT);
|
||||
out.Cat(tail);
|
||||
int cert_offset = out.GetLength() - 1;
|
||||
out.Cat('0', cert_length);
|
||||
int post_offset = out.GetLength() + 1;
|
||||
out << ">>>\n"
|
||||
"endobj\n";
|
||||
int root_off = out.GetLength();
|
||||
out
|
||||
<< new_root << " 0 obj\n"
|
||||
"<<" << pdfinfo.root_object
|
||||
<< "/AcroForm<</Fields[" << sign_object << " 0 R]/SigFlags 3>>>>\n"
|
||||
"endobj\n";
|
||||
int xref_offset = out.GetLength();
|
||||
out << "xref\n"
|
||||
<< sign_object << " 3\n"
|
||||
<< FormatIntDec(sign_off, 10, '0') << " 00000 n\r\n"
|
||||
<< FormatIntDec(dict_off, 10, '0') << " 00000 n\r\n"
|
||||
<< FormatIntDec(root_off, 10, '0') << " 00000 n\r\n"
|
||||
"trailer\n"
|
||||
"<</Size " << obj_index << "/Root " << new_root << " 0 R";
|
||||
if(!IsNull(pdfinfo.trailer_info))
|
||||
out << "/Info " << pdfinfo.trailer_info;
|
||||
out <<
|
||||
"/ID [ <" << Uuid::Create() << "> <" << Uuid::Create() << "> ]\n"
|
||||
"/Prev " << pdfinfo.startxref
|
||||
<< ">>\n"
|
||||
"startxref\n"
|
||||
<< xref_offset
|
||||
<< "\n"
|
||||
"%%EOF\n";
|
||||
int end_offset = out.GetLength();
|
||||
|
||||
String rcl_fmt = NFormat("%d %d %d ]", cert_offset,
|
||||
post_offset, end_offset - post_offset);
|
||||
ASSERT(rcl_fmt.GetLength() <= RCL_CONT);
|
||||
memcpy(out.Begin() + br_offset, rcl_fmt, rcl_fmt.GetLength());
|
||||
|
||||
Vector<const BYTE *> sections;
|
||||
Vector<DWORD> sizes;
|
||||
sections.SetCount(2);
|
||||
sizes.SetCount(2);
|
||||
sections[0] = (const BYTE *)out.Begin();
|
||||
sizes[0] = cert_offset;
|
||||
sections[1] = (const BYTE *)out.Begin() + post_offset;
|
||||
sizes[1] = end_offset - post_offset;
|
||||
int sig_len = 2 * CertSignLength(cert_context, sections, sizes);
|
||||
if(sig_len <= cert_length) {
|
||||
String signature = BinHexEncode(CertSign(cert_context, sections, sizes));
|
||||
ASSERT(signature.GetLength() <= cert_length);
|
||||
memcpy(out.Begin() + cert_offset + 1, signature, signature.GetLength());
|
||||
return out;
|
||||
}
|
||||
cert_length = sig_len;
|
||||
}
|
||||
}
|
||||
163
uppsrc/plugin/wincert/util.cpp
Normal file
163
uppsrc/plugin/wincert/util.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#include "wincert.h"
|
||||
|
||||
String CertGetProperty(PCCERT_CONTEXT cert_context, DWORD propertyID)
|
||||
{
|
||||
dword len = 0;
|
||||
if(!CertGetCertificateContextProperty(cert_context, propertyID, NULL, &len))
|
||||
return String::GetVoid();
|
||||
Buffer<byte> prop(len);
|
||||
if(!CertGetCertificateContextProperty(cert_context, propertyID, prop, &len))
|
||||
return String::GetVoid();
|
||||
return String(~prop, len);
|
||||
}
|
||||
|
||||
String CertGetName(PCCERT_CONTEXT cert_context, DWORD dwType, DWORD flags)
|
||||
{
|
||||
dword len = CertGetNameString(cert_context, dwType, flags, NULL, NULL, NULL);
|
||||
if(!len)
|
||||
return String::GetVoid();
|
||||
Buffer<char> name(len);
|
||||
if(!(len = CertGetNameString(cert_context, dwType, flags, NULL, name, len)))
|
||||
return String::GetVoid();
|
||||
return String(name, len - 1);
|
||||
}
|
||||
|
||||
String CertGetNameAttr(PCCERT_CONTEXT cert_context, const char *attrOID)
|
||||
{
|
||||
dword len = CertGetNameString(cert_context, CERT_NAME_ATTR_TYPE, 0, (void *)attrOID, NULL, NULL);
|
||||
if(!len)
|
||||
return String::GetVoid();
|
||||
Buffer<char> name(len);
|
||||
if(!(len = CertGetNameString(cert_context, CERT_NAME_ATTR_TYPE, 0, (void *)attrOID, name, len)))
|
||||
return String::GetVoid();
|
||||
return String(name, len - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
String CertGetHash(PCCERT_CONTEXT cert_context)
|
||||
{
|
||||
dword hash_len = 0;
|
||||
CertGetCertificateContextProperty(cert_context, CERT_HASH_PROP_ID, NULL, &hash_len);
|
||||
Buffer<byte> hash(hash_len);
|
||||
CertGetCertificateContextProperty(cert_context, CERT_HASH_PROP_ID, hash, &hash_len);
|
||||
String cert_hash(~hash, hash_len);
|
||||
return cert_hash;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
String CertGetName(PCCERT_CONTEXT cert_context)
|
||||
{
|
||||
dword type;
|
||||
dword len = CertGetNameString(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &type, NULL, NULL);
|
||||
Buffer<char> name(len);
|
||||
CertGetNameString(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &type, name, len);
|
||||
String cert_name(name, len ? len - 1 : 0);
|
||||
return cert_name;
|
||||
}
|
||||
*/
|
||||
|
||||
CertInfo CertGetInfo(PCCERT_CONTEXT cert_context)
|
||||
{
|
||||
CertInfo out;
|
||||
out.hash = CertGetProperty(cert_context, CERT_HASH_PROP_ID);
|
||||
out.common_name = CertGetNameAttr(cert_context, szOID_COMMON_NAME);
|
||||
out.organization = CertGetNameAttr(cert_context, szOID_ORGANIZATION_NAME);
|
||||
out.organizational_unit = CertGetNameAttr(cert_context, szOID_ORGANIZATIONAL_UNIT_NAME);
|
||||
out.email = CertGetNameAttr(cert_context, szOID_RSA_emailAddr);
|
||||
out.issuer = CertGetName(cert_context, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG);
|
||||
out.valid_from = Time(cert_context->pCertInfo->NotBefore);
|
||||
out.valid_until = Time(cert_context->pCertInfo->NotAfter);
|
||||
// out.valid_until = Cert
|
||||
return out;
|
||||
}
|
||||
|
||||
static void _sCertSignSet(PCCERT_CONTEXT cert_context, CRYPT_SIGN_MESSAGE_PARA& sign)
|
||||
{
|
||||
Zero(sign);
|
||||
sign.cbSize = sizeof(sign);
|
||||
sign.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
|
||||
sign.pSigningCert = cert_context;
|
||||
sign.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
|
||||
sign.HashAlgorithm.Parameters.cbData = NULL;
|
||||
sign.cMsgCert = 1;
|
||||
sign.rgpMsgCert = &sign.pSigningCert;
|
||||
sign.cAuthAttr = 0;
|
||||
sign.dwInnerContentType = 0;
|
||||
sign.cMsgCrl = 0;
|
||||
sign.cUnauthAttr = 0;
|
||||
sign.dwFlags = 0;
|
||||
sign.pvHashAuxInfo = NULL;
|
||||
sign.rgAuthAttr = NULL;
|
||||
}
|
||||
|
||||
int CertSignLength(PCCERT_CONTEXT cert_context, Vector<const BYTE *>& sections, Vector<DWORD>& sizes)
|
||||
{
|
||||
ASSERT(sections.GetCount() == sizes.GetCount());
|
||||
|
||||
CRYPT_SIGN_MESSAGE_PARA sign;
|
||||
|
||||
_sCertSignSet(cert_context, sign);
|
||||
|
||||
const BYTE **psect = sections.Begin();
|
||||
DWORD *psize = sizes.Begin();
|
||||
|
||||
DWORD out_size = 0;
|
||||
if(!CryptSignMessage(&sign, TRUE, sections.GetCount(), psect, psize, NULL, &out_size))
|
||||
return 0;
|
||||
return out_size;
|
||||
}
|
||||
|
||||
String CertSign(PCCERT_CONTEXT cert_context, Vector<const BYTE *>& sections, Vector<DWORD>& sizes)
|
||||
{
|
||||
ASSERT(sections.GetCount() == sizes.GetCount());
|
||||
|
||||
CRYPT_SIGN_MESSAGE_PARA sign;
|
||||
|
||||
_sCertSignSet(cert_context, sign);
|
||||
|
||||
const BYTE **psect = sections.Begin();
|
||||
DWORD *psize = sizes.Begin();
|
||||
|
||||
DWORD out_size = 0;
|
||||
if(!CryptSignMessage(&sign, TRUE, sections.GetCount(), psect, psize, NULL, &out_size))
|
||||
return String::GetVoid();
|
||||
Buffer<byte> out_data(out_size);
|
||||
if(!CryptSignMessage(&sign, TRUE, sections.GetCount(), psect, psize, out_data, &out_size))
|
||||
return String::GetVoid();
|
||||
|
||||
return String(~out_data, out_size);
|
||||
}
|
||||
|
||||
String CertSign(PCCERT_CONTEXT context, const String& message)
|
||||
{
|
||||
Vector<const BYTE *> sections;
|
||||
Vector<DWORD> sizes;
|
||||
sections.SetCount(1, (const BYTE *)message.Begin());
|
||||
sizes.SetCount(1, message.GetLength());
|
||||
return CertSign(context, sections, sizes);
|
||||
}
|
||||
|
||||
Array<CertInfo> CertEnum(HCERTSTORE store)
|
||||
{
|
||||
Array<CertInfo> out_list;
|
||||
|
||||
RLOG("store = " << FormatIntHex(store));
|
||||
|
||||
PCCERT_CONTEXT cert_context = NULL;
|
||||
while(cert_context = CertEnumCertificatesInStore(store, cert_context)) {
|
||||
out_list.Add() = CertGetInfo(cert_context);
|
||||
}
|
||||
|
||||
return out_list;
|
||||
}
|
||||
|
||||
PCCERT_CONTEXT CertFind(HCERTSTORE store, const String& hash)
|
||||
{
|
||||
CRYPT_HASH_BLOB hash_blob;
|
||||
hash_blob.pbData = (BYTE *)hash.Begin();
|
||||
hash_blob.cbData = hash.GetLength();
|
||||
|
||||
return CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
0, CERT_FIND_HASH, &hash_blob, NULL);
|
||||
}
|
||||
34
uppsrc/plugin/wincert/wincert.h
Normal file
34
uppsrc/plugin/wincert/wincert.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef _wincert_wincert_h
|
||||
#define _wincert_wincert_h
|
||||
|
||||
#include <Web/Web.h>
|
||||
#include <WinCrypt.h>
|
||||
|
||||
using namespace Upp;
|
||||
|
||||
struct CertInfo {
|
||||
String hash;
|
||||
String common_name;
|
||||
String organization;
|
||||
String organizational_unit;
|
||||
String email;
|
||||
String issuer;
|
||||
Time valid_from;
|
||||
Time valid_until;
|
||||
};
|
||||
|
||||
String CertGetProperty(PCCERT_CONTEXT cert_context, DWORD propertyID);
|
||||
String CertGetName(PCCERT_CONTEXT cert_context, DWORD dwType, DWORD flags = 0);
|
||||
String CertGetNameAttr(PCCERT_CONTEXT cert_context, const char *attrOID);
|
||||
CertInfo CertGetInfo(PCCERT_CONTEXT cert_context);
|
||||
|
||||
Array<CertInfo> CertEnum(HCERTSTORE store);
|
||||
PCCERT_CONTEXT CertFind(HCERTSTORE store, const String& hash);
|
||||
|
||||
int CertSignLength(PCCERT_CONTEXT cert_context, Vector<const BYTE *>& sections, Vector<DWORD>& sizes);
|
||||
String CertSign(PCCERT_CONTEXT cert_context, Vector<const BYTE *>& sections, Vector<DWORD>& sizes);
|
||||
String CertSign(PCCERT_CONTEXT context, const String& message);
|
||||
|
||||
String CertSignPDF(PCCERT_CONTEXT cert_context, const String& pdf_data);
|
||||
|
||||
#endif
|
||||
13
uppsrc/plugin/wincert/wincert.upp
Normal file
13
uppsrc/plugin/wincert/wincert.upp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
description "Minimum Win32 certificate support and PDF digital signing\377";
|
||||
|
||||
uses
|
||||
Web;
|
||||
|
||||
library
|
||||
Crypt32.lib;
|
||||
|
||||
file
|
||||
wincert.h,
|
||||
util.cpp,
|
||||
pdf.cpp;
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue