tdf#62032 use style list level when changing style
[LibreOffice.git] / hwpfilter / source / hwpfile.cxx
blob15f73fbec6ec27fd8562ede188ee036f735b5494
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include "precompile.h"
23 #include <algorithm>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
29 #include <o3tl/safeint.hxx>
31 #include "hwplib.h"
32 #include "hwpfile.h"
33 #include "hiodev.h"
34 #include "hfont.h"
35 #include "hstyle.h"
36 #include "hbox.h"
37 #include "hpara.h"
38 #include "htags.h"
39 #include "hcode.h"
40 #include "hstream.hxx"
43 HWPFile *HWPFile::cur_doc = nullptr;
44 static int ccount = 0;
45 static int pcount = 0;
46 static int datecodecount = 0;
48 HWPFile::HWPFile()
49 : version(HWP_V30)
50 , compressed(false)
51 , encrypted(false)
52 , linenumber(0)
53 , info_block_len(0)
54 , error_code(HWP_NoError)
55 , readdepth(0)
56 , m_nCurrentPage(1)
57 , m_nMaxSettedPage(0)
58 , currenthyper(0)
60 SetCurrentDoc(this);
63 HWPFile::~HWPFile()
65 oledata.reset();
66 hiodev.reset();
69 int HWPFile::ReadHwpFile(std::unique_ptr<HStream> stream)
71 if (Open(std::move(stream)) != HWP_NoError)
72 return State();
73 InfoRead();
74 FontRead();
75 StyleRead();
76 AddColumnInfo();
77 ParaListRead();
78 TagsRead();
80 return State();
83 int detect_hwp_version(const char *str)
85 if (memcmp(V20SIGNATURE, str, HWPIDLen) == 0)
86 return HWP_V20;
87 else if (memcmp(V21SIGNATURE, str, HWPIDLen) == 0)
88 return HWP_V21;
89 else if (memcmp(V30SIGNATURE, str, HWPIDLen) == 0)
90 return HWP_V30;
91 return 0;
94 // HIODev wrapper
96 int HWPFile::Open(std::unique_ptr<HStream> stream)
98 std::unique_ptr<HStreamIODev> hstreamio(new HStreamIODev(std::move(stream)));
100 if (!hstreamio->open())
102 return SetState(HWP_EMPTY_FILE);
105 SetIODevice(std::move(hstreamio));
107 char idstr[HWPIDLen];
109 if (ReadBlock(idstr, HWPIDLen) < HWPIDLen)
110 return SetState(HWP_UNSUPPORTED_VERSION);
111 version = detect_hwp_version(idstr);
112 if (HWP_V30 != version)
113 return SetState(HWP_UNSUPPORTED_VERSION);
114 return HWP_NoError;
117 int HWPFile::SetState(int errcode)
119 error_code = errcode;
120 return error_code;
123 bool HWPFile::Read1b(unsigned char &out)
125 return hiodev && hiodev->read1b(out);
128 bool HWPFile::Read1b(char &out)
130 unsigned char tmp8;
131 if (!hiodev || !hiodev->read1b(tmp8))
132 return false;
133 out = tmp8;
134 return true;
137 bool HWPFile::Read2b(unsigned short &out)
139 return hiodev && hiodev->read2b(out);
142 bool HWPFile::Read4b(unsigned int &out)
144 return hiodev && hiodev->read4b(out);
147 bool HWPFile::Read4b(int &out)
149 unsigned int tmp32;
150 if (!Read4b(tmp32))
151 return false;
152 out = tmp32;
153 return true;
156 size_t HWPFile::Read2b(void *ptr, size_t nmemb)
158 return hiodev ? hiodev->read2b(ptr, nmemb) : 0;
161 size_t HWPFile::ReadBlock(void *ptr, size_t size)
163 return hiodev ? hiodev->readBlock(ptr, size) : 0;
166 size_t HWPFile::SkipBlock(size_t size)
168 return hiodev ? hiodev->skipBlock(size) : 0;
171 void HWPFile::SetCompressed(bool flag)
173 if (hiodev)
174 hiodev->setCompressed(flag);
178 std::unique_ptr<HIODev> HWPFile::SetIODevice(std::unique_ptr<HIODev> new_hiodev)
180 std::swap(hiodev, new_hiodev);
181 return new_hiodev;
185 // end of HIODev wrapper
187 void HWPFile::InfoRead()
189 _hwpInfo.Read(*this);
193 void HWPFile::FontRead()
195 _hwpFont.Read(*this);
199 void HWPFile::StyleRead()
201 _hwpStyle.Read(*this);
205 void HWPFile::ParaListRead()
207 ReadParaList(plist);
210 void HWPFile::ReadParaList(std::vector < HWPPara* > &aplist)
212 std::unique_ptr<HWPPara> spNode( new HWPPara );
213 unsigned char tmp_etcflag;
214 unsigned char prev_etcflag = 0;
215 while (spNode->Read(*this, 0))
217 if( !(spNode->etcflag & 0x04) ){
218 tmp_etcflag = spNode->etcflag;
219 spNode->etcflag = prev_etcflag;
220 prev_etcflag = tmp_etcflag;
222 if (spNode->nch && spNode->reuse_shape)
224 if (!aplist.empty()){
225 spNode->pshape = aplist.back()->pshape;
227 else{
228 spNode->nch = 0;
229 spNode->reuse_shape = 0;
232 spNode->pshape->pagebreak = spNode->etcflag;
233 if (spNode->nch)
234 AddParaShape(spNode->pshape);
236 if (!aplist.empty())
237 aplist.back()->SetNext(spNode.get());
238 aplist.push_back(spNode.release());
239 spNode.reset( new HWPPara );
241 move_to_failed(std::move(spNode));
244 void HWPFile::ReadParaList(std::vector< std::unique_ptr<HWPPara> > &aplist, unsigned char flag)
246 std::unique_ptr<HWPPara> spNode( new HWPPara );
247 unsigned char tmp_etcflag;
248 unsigned char prev_etcflag = 0;
249 while (spNode->Read(*this, flag))
251 if( !(spNode->etcflag & 0x04) ){
252 tmp_etcflag = spNode->etcflag;
253 spNode->etcflag = prev_etcflag;
254 prev_etcflag = tmp_etcflag;
256 if (spNode->nch && spNode->reuse_shape)
258 if (!aplist.empty()){
259 spNode->pshape = aplist.back()->pshape;
261 else{
262 spNode->nch = 0;
263 spNode->reuse_shape = 0;
266 spNode->pshape->pagebreak = spNode->etcflag;
267 if (spNode->nch)
268 AddParaShape(spNode->pshape);
270 if (!aplist.empty())
271 aplist.back()->SetNext(spNode.get());
272 aplist.push_back(std::move(spNode));
273 spNode.reset( new HWPPara );
275 move_to_failed(std::move(spNode));
278 void HWPFile::move_to_failed(std::unique_ptr<HWPPara> xPara)
280 pfailedlist.push_back(std::move(xPara));
283 void HWPFile::TagsRead()
285 while (true)
287 uint tag;
288 if (!Read4b(tag))
289 return;
290 int size;
291 if (!Read4b(size))
292 return;
293 if (size <= 0 && tag > 0){
294 continue;
297 if (tag == FILETAG_END_OF_COMPRESSED ||
298 tag == FILETAG_END_OF_UNCOMPRESSED)
299 return;
300 switch (tag)
302 case FILETAG_EMBEDDED_PICTURE:
304 std::unique_ptr<EmPicture> emb(new EmPicture(size));
306 if (emb->Read(*this))
307 emblist.push_back(std::move(emb));
309 break;
310 case FILETAG_OLE_OBJECT:
311 oledata.reset( new OlePicture(size) );
312 oledata->Read(*this);
313 break;
314 case FILETAG_HYPERTEXT:
316 const int nRecordLen = 617;
317 if( (size % nRecordLen) != 0 )
318 SkipBlock( size );
319 else
321 const int nRecords = size / nRecordLen;
322 for (int i = 0 ; i < nRecords; ++i)
324 std::unique_ptr<HyperText> hypert(new HyperText);
325 if (hypert->Read(*this))
326 hyperlist.push_back(std::move(hypert));
327 else
328 break;
331 break;
333 case 6:
335 ReadBlock(_hwpInfo.back_info.reserved1, 8);
336 if (!Read4b(_hwpInfo.back_info.luminance))
337 return;
338 if (!Read4b(_hwpInfo.back_info.contrast))
339 return;
340 if (!Read1b(_hwpInfo.back_info.effect))
341 return;
342 ReadBlock(_hwpInfo.back_info.reserved2, 7);
343 ReadBlock(_hwpInfo.back_info.filename, 260);
344 ReadBlock(_hwpInfo.back_info.color, 3);
345 unsigned short nFlag;
346 if (!Read2b(nFlag))
347 return;
348 _hwpInfo.back_info.flag = nFlag >> 8 ;
349 int nRange;
350 if (!Read4b(nRange))
351 return;
352 _hwpInfo.back_info.range = nRange >> 24;
353 ReadBlock(_hwpInfo.back_info.reserved3, 27);
354 if (!Read4b(_hwpInfo.back_info.size))
355 return;
357 if (_hwpInfo.back_info.size < 0)
359 _hwpInfo.back_info.size = 0;
360 return;
363 _hwpInfo.back_info.data.clear();
365 //read potentially compressed data in blocks as it's more
366 //likely large values are simply broken and we'll run out
367 //of data before we need to realloc
368 for (int i = 0; i < _hwpInfo.back_info.size; i+= SAL_MAX_UINT16)
370 int nOldSize = _hwpInfo.back_info.data.size();
371 size_t nBlock = std::min<int>(SAL_MAX_UINT16, _hwpInfo.back_info.size - nOldSize);
372 _hwpInfo.back_info.data.resize(nOldSize + nBlock);
373 size_t nReadBlock = ReadBlock(_hwpInfo.back_info.data.data() + nOldSize, nBlock);
374 if (nBlock != nReadBlock)
376 _hwpInfo.back_info.data.resize(nOldSize + nReadBlock);
377 break;
380 _hwpInfo.back_info.size = _hwpInfo.back_info.data.size();
382 if( _hwpInfo.back_info.size > 0 )
383 _hwpInfo.back_info.type = 2;
384 else if( _hwpInfo.back_info.filename[0] )
385 _hwpInfo.back_info.type = 1;
386 else
387 _hwpInfo.back_info.type = 0;
390 _hwpInfo.back_info.isset = true;
392 break;
394 case FILETAG_PRESENTATION:
395 case FILETAG_PREVIEW_IMAGE:
396 case FILETAG_PREVIEW_TEXT:
397 default:
398 SkipBlock(size);
404 ColumnDef *HWPFile::GetColumnDef(int num)
406 if (o3tl::make_unsigned(num) < columnlist.size())
407 return columnlist[num]->xColdef.get();
408 else
409 return nullptr;
412 /* Index of @return starts from 1 */
413 int HWPFile::GetPageMasterNum(int page)
415 int i = 0;
416 for (auto const& column : columnlist)
418 if( page < column->start_page )
419 return i;
420 ++i;
422 return i;
425 HyperText *HWPFile::GetHyperText()
427 ++currenthyper;
428 if (o3tl::make_unsigned(currenthyper) <= hyperlist.size())
429 return hyperlist[currenthyper-1].get();
430 else
431 return nullptr;
434 EmPicture *HWPFile::GetEmPicture(Picture * pic)
436 char *name = pic->picinfo.picembed.embname;
438 name[0] = 'H';
439 name[1] = 'W';
440 name[2] = 'P';
442 for (auto const& emb : emblist)
443 if (strcmp(name, emb->name) == 0)
444 return emb.get();
445 return nullptr;
448 EmPicture *HWPFile::GetEmPictureByName(char * name)
450 name[0] = 'H';
451 name[1] = 'W';
452 name[2] = 'P';
454 for (auto const& emb : emblist)
455 if (strcmp(name, emb->name) == 0)
456 return emb.get();
457 return nullptr;
460 void HWPFile::AddBox(FBox * box)
462 blist.push_back(box);
465 ParaShape *HWPFile::getParaShape(int index)
467 if (index < 0 || o3tl::make_unsigned(index) >= pslist.size())
468 return nullptr;
469 return pslist[index].get();
472 CharShape *HWPFile::getCharShape(int index)
474 if (index < 0 || o3tl::make_unsigned(index) >= cslist.size())
475 return nullptr;
476 return cslist[index].get();
479 FBoxStyle *HWPFile::getFBoxStyle(int index)
481 if (index < 0 || o3tl::make_unsigned(index) >= fbslist.size())
482 return nullptr;
483 return fbslist[index];
486 DateCode *HWPFile::getDateCode(int index)
488 if (index < 0 || o3tl::make_unsigned(index) >= datecodes.size())
489 return nullptr;
490 return datecodes[index];
493 HeaderFooter *HWPFile::getHeaderFooter(int index)
495 if (index < 0 || o3tl::make_unsigned(index) >= headerfooters.size())
496 return nullptr;
497 return headerfooters[index];
500 ShowPageNum *HWPFile::getPageNumber(int index)
502 if (index < 0 || o3tl::make_unsigned(index) >= pagenumbers.size())
503 return nullptr;
504 return pagenumbers[index];
507 Table *HWPFile::getTable(int index)
509 if (index < 0 || o3tl::make_unsigned(index) >= tables.size())
510 return nullptr;
511 return tables[index].get();
514 void HWPFile::AddParaShape(std::shared_ptr<ParaShape> const & pshape)
516 int nscount = 0;
517 for(int j = 0 ; j < MAXTABS-1 ; j++)
519 if( j > 0 && pshape->tabs[j].position == 0 )
520 break;
521 if( pshape->tabs[0].position == 0 ){
522 if( pshape->tabs[j].type || pshape->tabs[j].dot_continue ||
523 (pshape->tabs[j].position != 1000 *j) )
524 nscount = j;
526 else {
527 if( pshape->tabs[j].type || pshape->tabs[j].dot_continue ||
528 (pshape->tabs[j].position != 1000 * (j + 1)) )
529 nscount = j;
532 if( nscount )
534 pshape->tabs[MAXTABS-1].type = sal::static_int_cast<char>(nscount);
535 pshape->index = ++pcount;
536 pslist.push_back(pshape);
537 return;
540 int value = compareParaShape(pshape.get());
541 if (value == 0)
543 pshape->index = ++pcount;
544 pslist.push_back(pshape);
545 return;
547 pshape->index = value;
550 void HWPFile::AddCharShape(std::shared_ptr<CharShape> const & cshape)
552 int value = compareCharShape(cshape.get());
553 if (value == 0)
555 cshape->index = ++ccount;
556 cslist.push_back(cshape);
558 else
559 cshape->index = value;
562 void HWPFile::AddColumnInfo()
564 columnlist.emplace_back(new ColumnInfo(m_nCurrentPage));
565 setMaxSettedPage();
568 void HWPFile::SetColumnDef(const std::shared_ptr<ColumnDef>& rColdef)
570 ColumnInfo *cinfo = columnlist.back().get();
571 if( cinfo->bIsSet )
572 return;
573 cinfo->xColdef = rColdef;
574 cinfo->bIsSet = true;
577 void HWPFile::AddDateFormat(DateCode * hbox)
579 hbox->key = sal::static_int_cast<char>(++datecodecount);
580 datecodes.push_back(hbox);
583 void HWPFile::AddPageNumber(ShowPageNum * hbox)
585 pagenumbers.push_back(hbox);
588 void HWPFile::AddHeaderFooter(HeaderFooter * hbox)
590 headerfooters.push_back(hbox);
593 void HWPFile::AddTable(std::unique_ptr<Table> hbox)
595 tables.push_back(std::move(hbox));
598 void HWPFile::AddFBoxStyle(FBoxStyle * fbstyle)
600 fbslist.push_back(fbstyle);
603 int HWPFile::compareCharShape(CharShape const *shape)
605 int count = cslist.size();
606 if( count > 0 )
608 for(int i = 0; i< count; i++)
610 CharShape *cshape = getCharShape(i);
612 if( shape->size == cshape->size &&
613 shape->font[0] == cshape->font[0] &&
614 shape->ratio[0] == cshape->ratio[0] &&
615 shape->space[0] == cshape->space[0] &&
616 shape->color[1] == cshape->color[1] &&
617 shape->color[0] == cshape->color[0] &&
618 shape->shade == cshape->shade &&
619 shape->attr == cshape->attr )
621 return cshape->index;
625 return 0;
628 int HWPFile::compareParaShape(const ParaShape* shape)
630 if (!shape->cshape)
631 return 0;
633 int count = pslist.size();
634 for (int i = 0; i < count; ++i)
636 ParaShape *pshape = pslist[i].get();
637 if (!pshape->cshape)
638 continue;
639 if (shape->left_margin == pshape->left_margin &&
640 shape->right_margin == pshape->right_margin &&
641 shape->pspacing_prev == pshape->pspacing_prev &&
642 shape->pspacing_next == pshape->pspacing_next &&
643 shape->indent == pshape->indent &&
644 shape->lspacing == pshape->lspacing &&
645 shape->arrange_type == pshape->arrange_type &&
646 shape->outline == pshape->outline &&
647 shape->pagebreak == pshape->pagebreak)
649 if (shape->cshape->size == pshape->cshape->size &&
650 shape->cshape->font[0] == pshape->cshape->font[0] &&
651 shape->cshape->ratio[0] == pshape->cshape->ratio[0] &&
652 shape->cshape->space[0] == pshape->cshape->space[0] &&
653 shape->cshape->color[1] == pshape->cshape->color[1] &&
654 shape->cshape->color[0] == pshape->cshape->color[0] &&
655 shape->cshape->shade == pshape->cshape->shade &&
656 shape->cshape->attr == pshape->cshape->attr)
658 return pshape->index;
662 return 0;
665 HWPFile *GetCurrentDoc()
667 return HWPFile::cur_doc;
671 HWPFile *SetCurrentDoc(HWPFile * hwpfp)
673 HWPFile *org = HWPFile::cur_doc;
675 HWPFile::cur_doc = hwpfp;
676 return org;
679 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */