/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include "precompile.h"
 
#include <comphelper/newarray.hxx>
#include <comphelper/configuration.hxx>
#include <sal/log.hxx>
#include <tools/long.hxx>
 
#include <assert.h>
 
#include "hwpfile.h"
#include "hbox.h"
#include "hpara.h"
#include "drawing.h"
#include "htags.h"
#include "hcode.h"
 
static short fboxnum = 1;
static int zindex = 1;
static int lnnumber = 0;
 
bool HBox::Read(HWPFile & )
{
    // already read
    return true;
}
 
// skip block
bool SkipData::Read(HWPFile & hwpf)
{
    uint data_block_len;
    hwpf.Read4b(data_block_len);
 
    hchar dummy;
    if (!hwpf.Read2b(dummy))
        return hwpf.SetState(HWP_InvalidFileFormat);
 
    if (!(IS_SP_SKIP_BLOCK(hh) && (hh == dummy))){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    return hwpf.SkipBlock(data_block_len);
}
 
// Field code(5)
bool FieldCode::Read(HWPFile & hwpf)
{
    uint size;
    hchar dummy;
    uint len1;       /* Length of hchar type string DATA #1 */
    uint len2;       /* Length of hchar type string DATA #2 */
    uint len3;       /* Length of hchar type string DATA #3 */
    uint binlen;     /* Length of any binary data format */
 
    hwpf.Read4b(size);
    if (!hwpf.Read2b(dummy))
        return false;
    hwpf.ReadBlock(&type, 2);
    hwpf.ReadBlock(reserved1.data(), 4);
    if (!hwpf.Read2b(location_info))
        return false;
    hwpf.ReadBlock(reserved2.data(), 22);
    hwpf.Read4b(len1);
    hwpf.Read4b(len2);
    hwpf.Read4b(len3);
    if (!hwpf.Read4b(binlen))
        return false;
 
    uint const len1_ = std::min<uint>(len1, 1024) / sizeof(hchar);
    uint const len2_ = std::min<uint>(len2, 1024) / sizeof(hchar);
    uint const len3_ = std::min<uint>(len3, 1024) / sizeof(hchar);
 
    str1.reset( new hchar[len1_ ? len1_ : 1] );
    str2.reset( new hchar[len2_ ? len2_ : 1] );
    str3.reset( new hchar[len3_ ? len3_ : 1] );
 
    if (hwpf.Read2b(str1.get(), len1_) != len1_)
        return false;
    hwpf.SkipBlock(len1 - (len1_ * sizeof(hchar)));
    str1[len1_ ? (len1_ - 1) : 0] = 0;
    if (hwpf.Read2b(str2.get(), len2_) != len2_)
        return false;
    hwpf.SkipBlock(len2 - (len2_ * sizeof(hchar)));
    str2[len2_ ? (len2_ - 1) : 0] = 0;
    if (hwpf.Read2b(str3.get(), len3_) != len3_)
        return false;
    hwpf.SkipBlock(len3 - (len3_ * sizeof(hchar)));
    str3[len3_ ? (len3_ - 1) : 0] = 0;
 
    hwpf.SkipBlock(binlen);
 
    if( type[0] == 3 && type[1] == 2 ){ /* It must create a format as created date. */
          DateCode *pDate = new DateCode;
          for (uint i = 0 ; i < len3_; i++) {
                if(str3[i] == 0 ) break;
                if( i >= DATE_SIZE ) break;
                pDate->format[i] = str3[i];
          }
          hwpf.AddDateFormat(pDate);
          m_pDate.reset( pDate );
    }
 
    return true;
}
 
// book mark(6)
bool Bookmark::Read(HWPFile & hwpf)
{
    uint len;
 
    hwpf.Read4b(len);
    if (!hwpf.Read2b(dummy))
        return false;
 
    if (len != 34)// 2 * (BMK_COMMENT_LEN + 1) + 2
    {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    if (hh != dummy || dummy != CH_BOOKMARK) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    hwpf.Read2b(id, BMK_COMMENT_LEN + 1);
    hwpf.Read2b(&type, 1);
    return true;
}
 
// date format(7)
bool DateFormat::Read(HWPFile & hwpf)
{
    hwpf.Read2b(format, DATE_SIZE);
    if (!hwpf.Read2b(dummy))
        return false;
    if (hh != dummy || CH_DATE_FORM != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return true;
}
 
// date code(8)
bool DateCode::Read(HWPFile & hwpf)
{
    hwpf.Read2b(format, DATE_SIZE);
    hwpf.Read2b(date, 6);
    if (!hwpf.Read2b(dummy))
        return false;
    if (hh != dummy || CH_DATE_CODE != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    hwpf.AddDateFormat(this);
    return true;
}
 
// tab(9)
bool Tab::Read(HWPFile & hwpf)
{
    unsigned short tmp16;
    if (!hwpf.Read2b(tmp16))
        return false;
    width = tmp16;
    if (!hwpf.Read2b(leader))
        return false;
    if (!hwpf.Read2b(dummy))
        return false;
    if (hh != dummy || CH_TAB != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return true;
}
 
// tbox(10) TABLE BOX MATH BUTTON HYPERTEXT
static void UpdateBBox(FBox * fbox)
{
    fbox->boundsy = fbox->pgy;
    fbox->boundey = fbox->pgy + fbox->ys - 1;
}
 
bool Cell::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&p, 1);
    hwpf.Read2b(&color, 1);
    hwpf.Read2b(&x, 1);
    hwpf.Read2b(&y, 1);
    hwpf.Read2b(&w, 1);
    hwpf.Read2b(&h, 1);
    hwpf.Read2b(&txthigh, 1);
    hwpf.Read2b(&cellhigh, 1);
 
    hwpf.Read1b(flag);
    hwpf.Read1b(changed);
    hwpf.Read1b(used);
    hwpf.Read1b(ver_align);
    hwpf.ReadBlock(linetype, 4);
    hwpf.Read1b(shade);
    hwpf.Read1b(diagonal);
    return hwpf.Read1b(protect);
}
 
bool TxtBox::Read(HWPFile & hwpf)
{
    int ii, ncell;
 
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy || CH_TEXT_BOX != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    hwpf.Read2b(&style.cap_len, 1);
    hwpf.Read2b(&dummy1, 1);
    unsigned short next;
    hwpf.Read2b(&next, 1);
    hwpf.Read2b(&dummy2, 1);
 
    style.boxnum = fboxnum++;
    zorder = zindex++;
    hwpf.Read1b(style.anchor_type);
    hwpf.Read1b(style.txtflow);
    hwpf.Read2b(&style.xpos, 1);
    hwpf.Read2b(&style.ypos, 1);
    hwpf.Read2b(&option, 1);
    hwpf.Read2b(&ctrl_ch, 1);
    hwpf.Read2b(style.margin, 12);
    hwpf.Read2b(&box_xs, 1);
    hwpf.Read2b(&box_ys, 1);
    hwpf.Read2b(&cap_xs, 1);
    hwpf.Read2b(&cap_ys, 1);
    hwpf.Read2b(&style.cap_len, 1);
    hwpf.Read2b(&xs, 1);
    hwpf.Read2b(&ys, 1);
    hwpf.Read2b(&cap_margin, 1);
    hwpf.Read1b(xpos_type);
    hwpf.Read1b(ypos_type);
    hwpf.Read1b(smart_linesp);
    hwpf.Read1b(reserved1);
    hwpf.Read2b(&pgx, 1);
    hwpf.Read2b(&pgy, 1);
    hwpf.Read2b(&pgno, 1);
    if( ( pgno +1 ) != hwpf.getCurrentPage() )
          pgno = sal::static_int_cast<short>(hwpf.getCurrentPage() -1) ;
 
    hwpf.Read2b(&showpg, 1);
    hwpf.Read2b(&cap_pos, 1);
    hwpf.Read2b(&num, 1);
    hwpf.Read2b(&dummy3, 1);
    hwpf.Read2b(&baseline, 1);
    hwpf.Read2b(&type, 1);
    hwpf.Read2b(&nCell, 1);
    hwpf.Read2b(&protect, 1);
    switch (type)
    {
        case 0:                                   //table
            style.boxtype = 'T';
            break;
        case 1:                                   // text-box
            style.boxtype = 'X';
            break;
        case 2:                                   // equation
            style.boxtype = 'E';
            break;
        case 3:                                   // button
            style.boxtype = 'B';
            break;
        default:                                  // other
            style.boxtype = 'O';
            break;
    }
 
    UpdateBBox(this);
 
    ncell = nCell;
    if (ncell <= 0) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    if (ncell > 4096 && comphelper::IsFuzzing()) {
        // cut off at an arbitrary size to speed up fuzzing
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    cell.reset( ::comphelper::newArray_null<Cell>(ncell) );
    if (!cell) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    bool bSuccess = true;
    for (ii = 0; ii < ncell && bSuccess; ii++)
    {
        bSuccess = cell[ii].Read(hwpf);
        cell[ii].key = sal::static_int_cast<unsigned char>(ii);
    }
    if (!bSuccess)
        return false;
    if (ncell == 1)
        style.cell = &cell[0];
    plists.resize(ncell);
    for (ii = 0; ii < ncell; ii++)
        hwpf.ReadParaList(plists[ii]);
     // caption
    hwpf.ReadParaList(caption);
 
    if( type == 0 ){ // if table?
        std::unique_ptr<TCell*[]> pArr(new TCell*[ncell]);
        std::fill(pArr.get(), pArr.get() + ncell, nullptr);
        if (!pArr) {
              return hwpf.SetState(HWP_InvalidFileFormat);
        }
        std::unique_ptr<Table> tbl(new Table);
        for( ii = 0 ; ii < ncell; ii++)
        {
            tbl->columns.insert(cell[ii].x);
            tbl->columns.insert(cell[ii].x + cell[ii].w);
            tbl->rows.insert(cell[ii].y);
            tbl->rows.insert(cell[ii].y + cell[ii].h);
        }
        for( ii = 0 ; ii < ncell; ii++)
        {
            TCell *tcell = new TCell;
            tcell->nColumnIndex = tbl->columns.getIndex(cell[ii].x);
            tcell->nColumnSpan = tbl->columns.getIndex(cell[ii].x + cell[ii].w) -
                tcell->nColumnIndex;
            tcell->nRowIndex = tbl->rows.getIndex(cell[ii].y);
            tcell->nRowSpan = tbl->rows.getIndex(cell[ii].y + cell[ii].h) -
                tcell->nRowIndex;
            tcell->pCell = &cell[ii];
            pArr[ii] = tcell;
        }
 
        // Sort by row and column
        for( ii = 0 ; ii < ncell - 1; ii++ ){
            for( int jj = ii ; jj < ncell ; jj++){
               if( pArr[ii]->nRowIndex > pArr[jj]->nRowIndex ){
                    std::swap(pArr[ii], pArr[jj]);
               }
            }
            for( int kk = ii ; kk > 0 ; kk--){
               if( ( pArr[kk]->nRowIndex == pArr[kk-1]->nRowIndex ) &&
                      (pArr[kk]->nColumnIndex < pArr[kk-1]->nColumnIndex )){
                    std::swap(pArr[kk], pArr[kk-1]);
               }
            }
        }
        for( ii = 0 ; ii < ncell ; ii++ ){
            tbl->cells.emplace_back(pArr[ii]);
        }
        tbl->box = this;
        m_pTable = tbl.get();
        hwpf.AddTable(std::move(tbl));
    }
    else
        m_pTable = nullptr;
 
    bSuccess = !hwpf.State();
    if (bSuccess)
        hwpf.AddFBoxStyle(&style);
    return bSuccess;
}
 
namespace
{
    class ChangeMemGuard
    {
    private:
        HIODev* m_pOldMem;
        std::unique_ptr<HMemIODev> m_xNewMem;
    public:
        ChangeMemGuard(unsigned char* data, size_t nLen)
            : m_pOldMem(hmem)
            , m_xNewMem(std::make_unique<HMemIODev>(reinterpret_cast<char*>(data), nLen))
        {
            hmem = m_xNewMem.get();
        }
        ~ChangeMemGuard()
        {
            assert(hmem == m_xNewMem.get());
            hmem = m_pOldMem;
        }
    };
}
 
// picture(11)
bool Picture::Read(HWPFile & hwpf)
{
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy || CH_PICTURE != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    hwpf.Read4b(follow_block_size);
 
    //when fuzzing with a max len set, max decompress to 10 times that limit
    static size_t nMaxAllowedDecompression = [](const char* pEnv) { size_t nRet = pEnv ? std::atoi(pEnv) : 0; return nRet * 10; }(std::getenv("FUZZ_MAX_INPUT_LEN"));
 
    hwpf.Read2b(&dummy1, 1);                      /* Reserved 4 bytes */
    hwpf.Read2b(&dummy2, 1);
 
    style.boxnum = fboxnum++;
    zorder = zindex++;
    hwpf.Read1b(style.anchor_type);               /* Reference position */
    hwpf.Read1b(style.txtflow);                   /* Avoid painting. 0-2 (seat occupied, transparency, harmony) */
    hwpf.Read2b(&style.xpos, 1);                  /* Horizontal position: 1=left, 2=right, 3=center, and others=any */
    hwpf.Read2b(&style.ypos, 1);                  /* Vertical position: 1=top, 2=down, 3=middle, and others=any */
    hwpf.Read2b(&option, 1);                      /* Other options: Borders, reverse picture, and so on. Save as bit. */
    hwpf.Read2b(&ctrl_ch, 1);                     /* Always 11 */
    hwpf.Read2b(style.margin, 12);                /* Margin: [0-2] [] out / in / cell, [], [0-3] left / right / top / bottom margins */
    hwpf.Read2b(&box_xs, 1);                      /* Box Size Width */
    hwpf.Read2b(&box_ys, 1);                      /* Vertical */
    hwpf.Read2b(&cap_xs, 1);                      /* Caption Size Width */
    hwpf.Read2b(&cap_ys, 1);                      /* Vertical */
    hwpf.Read2b(&style.cap_len, 1);               /* Length */
    hwpf.Read2b(&xs, 1);                          /* The total size (box size + caption + margin) Horizontal */
    hwpf.Read2b(&ys, 1);                          /* Vertical */
    hwpf.Read2b(&cap_margin, 1);                  /* Caption margins */
    hwpf.Read1b(xpos_type);
    hwpf.Read1b(ypos_type);
    hwpf.Read1b(smart_linesp);                    /* Line Spacing protection: 0 unprotected 1 protected */
    hwpf.Read1b(reserved1);
    hwpf.Read2b(&pgx, 1);                         /* Real Calculated box width */
    hwpf.Read2b(&pgy, 1);                         /* Height */
    hwpf.Read2b(&pgno, 1);                        /* Page number: starts from 0 */
    hwpf.Read2b(&showpg, 1);                      /* Show the Box */
    hwpf.Read2b(&cap_pos, 1);                     /* Caption positions 0-7 Menu Order. */
    hwpf.Read2b(&num, 1);                         /* Box number, serial number which starts from 0 */
 
    hwpf.Read1b(pictype);                         /* Picture type */
 
    unsigned short tmp16;
    if (!hwpf.Read2b(tmp16))                      /* the real horizontal starting point where shows the picture */
        return false;
    skip[0] = tmp16;
    if (!hwpf.Read2b(tmp16))                      /* Vertical */
        return false;
    skip[1] = tmp16;
    if (!hwpf.Read2b(tmp16))                      /* Zoom Ratio: 0:fixed, others are percentage for horizontal */
        return false;
    scale[0] = tmp16;
    if (!hwpf.Read2b(tmp16))                      /* Vertical */
        return false;
    scale[1] = tmp16;
 
    hwpf.ReadBlock(picinfo.picun.path, 256);      /* Picture File Name: when type is not a Drawing. */
    picinfo.picun.path[255] = 0; // ensure null terminated
    hwpf.ReadBlock(reserved3, 9);                 /* Brightness / Contrast / Picture Effect, etc. */
 
    UpdateBBox(this);
    if( pictype != PICTYPE_DRAW )
        style.cell = reserved3;
    else
    {
        //picinfo.picun read above is unioned with
        //picinfo.picdraw and so wrote to the hdo pointer
        //value, which is definitely not useful to us
        picinfo.picdraw.hdo = nullptr;
    }
 
    if (follow_block_size != 0)
    {
        follow.clear();
 
        //read potentially compressed data in blocks as it's more
        //likely large values are simply broken and we'll run out
        //of data before we need to realloc
        for (size_t i = 0; i < follow_block_size; i+= SAL_N_ELEMENTS(hwpf.scratch))
        {
           size_t nOldSize = follow.size();
           size_t nBlock = std::min(SAL_N_ELEMENTS(hwpf.scratch), follow_block_size - nOldSize);
           size_t nReadBlock = hwpf.ReadBlock(hwpf.scratch, nBlock);
           if (nReadBlock)
           {
               follow.insert(follow.end(), hwpf.scratch, hwpf.scratch + nReadBlock);
           }
           if (nBlock != nReadBlock)
               break;
           if (nMaxAllowedDecompression && follow.size() > nMaxAllowedDecompression)
           {
               SAL_WARN("filter.hwp", "too much decompression, abandoning");
               follow.clear();
               return false;
           }
        }
        follow_block_size = follow.size();
 
        if (pictype == PICTYPE_DRAW)
        {
            ChangeMemGuard aGuard(follow.data(), follow_block_size);
            LoadDrawingObjectBlock(this, hwpf);
            style.cell = picinfo.picdraw.hdo;
        }
        else if (follow_block_size >= 4)
        {
            if ((follow[3] << 24 | follow[2] << 16 | follow[1] << 8 | follow[0]) == 0x269)
            {
                ishyper = true;
            }
        }
    }
 
    if( pictype != 3 )
        style.boxtype = 'G';
    else
        style.boxtype = 'D';
 
// caption
    hwpf.ReadParaList(caption);
 
    bool bSuccess = !hwpf.State();
    if (bSuccess)
        hwpf.AddFBoxStyle(&style);
    return bSuccess;
}
 
// line(15)
Line::Line()
    : FBox(CH_LINE)
    , dummy(0)
    , sx(0)
    , sy(0)
    , ex(0)
    , ey(0)
    , width(0)
    , shade(0)
    , color(0)
{
}
 
bool Line::Read(HWPFile & hwpf)
{
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy || CH_LINE != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    style.boxnum = fboxnum++;
    zorder = zindex++;
    style.boxtype = 'L';
    hwpf.ReadBlock(&reserved2, 8);
    hwpf.Read1b(style.anchor_type);
    hwpf.Read1b(style.txtflow);
    hwpf.Read2b(&style.xpos, 1);
    hwpf.Read2b(&style.ypos, 1);
    hwpf.Read2b(&option, 1);
    hwpf.Read2b(&ctrl_ch, 1);
    hwpf.Read2b(style.margin, 12);
    hwpf.Read2b(&box_xs, 1);
    hwpf.Read2b(&box_ys, 1);
    hwpf.Read2b(&cap_xs, 1);
    hwpf.Read2b(&cap_ys, 1);
    hwpf.Read2b(&style.cap_len, 1);
    hwpf.Read2b(&xs, 1);
    hwpf.Read2b(&ys, 1);
    lnnumber = style.boxnum;
    hwpf.linenumber = 1;
    hwpf.Read2b(&boundsy, 1);
    hwpf.Read2b(&boundey, 1);
    hwpf.Read1b(boundx);
    hwpf.Read1b(draw);
 
    hwpf.Read2b(&pgx, 1);
    hwpf.Read2b(&pgy, 1);
    hwpf.Read2b(&pgno, 1);
    hwpf.Read2b(&showpg, 1);
 
    hwpf.Read2b(&sx, 1);
    hwpf.Read2b(&sy, 1);
    hwpf.Read2b(&ex, 1);
    hwpf.Read2b(&sy, 1);
    hwpf.Read2b(&width, 1);
    hwpf.Read2b(&shade, 1);
    hwpf.Read2b(&color, 1);
    style.xpos = width;
 
    bool bSuccess = !hwpf.State();
    if (bSuccess)
        hwpf.AddFBoxStyle(&style);
    return bSuccess;
}
 
// hidden(15)
Hidden::Hidden()
    : HBox(CH_HIDDEN)
    , dummy(0)
{
}
 
bool Hidden::Read(HWPFile & hwpf)
{
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
    if (hh != dummy || CH_HIDDEN != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    hwpf.ReadBlock(info, 8);
    hwpf.ReadParaList(plist);
 
    return !hwpf.State();
}
 
// header/footer(16)
HeaderFooter::HeaderFooter()
    : HBox(CH_HEADER_FOOTER)
    , dummy(0)
    , type(0)
    , where(0)
    , linenumber(0)
    , m_nPageNumber(0)
{
}
 
bool HeaderFooter::Read(HWPFile & hwpf)
{
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
    if (hh != dummy || CH_HEADER_FOOTER != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    hwpf.ReadBlock(info, 8);
    hwpf.Read1b(type);
    hwpf.Read1b(where);
    lnnumber = 0;
    hwpf.ReadParaList(plist, CH_HEADER_FOOTER);
    linenumber = sal::static_int_cast<unsigned char>(lnnumber);
    m_nPageNumber = hwpf.getCurrentPage();
    hwpf.setMaxSettedPage();
    hwpf.AddHeaderFooter(this);
 
    return !hwpf.State();
}
 
 
// footnote(17)
Footnote::Footnote()
    : HBox(CH_FOOTNOTE)
    , dummy(0)
    , number(0)
    , type(0)
    , width(0)
{
}
 
bool Footnote::Read(HWPFile & hwpf)
{
    hwpf.Read2b(reserved, 2);
    hwpf.Read2b(&dummy, 1);
    if (hh != dummy || CH_FOOTNOTE != dummy) {
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
 
    hwpf.ReadBlock(info, 8);
    hwpf.Read2b(&number, 1);
    hwpf.Read2b(&type, 1);
    unsigned short tmp16;
    if (!hwpf.Read2b(tmp16))
        return false;
    width = tmp16;
    hwpf.ReadParaList(plist, CH_FOOTNOTE);
 
    return !hwpf.State();
}
 
// auto number(18)
AutoNum::AutoNum()
    : HBox(CH_AUTO_NUM)
    , type(0)
    , number(0)
    , dummy(0)
{
}
 
bool AutoNum::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&type, 1);
    hwpf.Read2b(&number, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
 
// new number(19)
NewNum::NewNum()
    : HBox(CH_NEW_NUM)
    , type(0)
    , number(0)
    , dummy(0)
{
}
 
 
bool NewNum::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&type, 1);
    hwpf.Read2b(&number, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// show page number (20)
ShowPageNum::ShowPageNum()
    : HBox(CH_SHOW_PAGE_NUM)
    , where(0)
    , m_nPageNumber(0)
    , shape(0)
    , dummy(0)
{
}
 
bool ShowPageNum::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&where, 1);
    hwpf.Read2b(&shape, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    m_nPageNumber = hwpf.getCurrentPage();
    hwpf.setMaxSettedPage();
    hwpf.AddPageNumber(this);
    return !hwpf.State();
}
 
/* 홀수쪽시작/감추기 (21) */
PageNumCtrl::PageNumCtrl()
    : HBox(CH_PAGE_NUM_CTRL)
    , kind(0)
    , what(0)
    , dummy(0)
{
}
 
bool PageNumCtrl::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&kind, 1);
    hwpf.Read2b(&what, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// mail merge(22)
MailMerge::MailMerge()
    : HBox(CH_MAIL_MERGE)
    , dummy(0)
{
}
 
bool MailMerge::Read(HWPFile & hwpf)
{
    hwpf.ReadBlock(field_name, 20);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// char composition(23)
Compose::Compose()
    : HBox(CH_COMPOSE)
    , dummy(0)
{
}
 
bool Compose::Read(HWPFile & hwpf)
{
    hwpf.Read2b(compose, 3);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// hyphen(24)
Hyphen::Hyphen()
    : HBox(CH_HYPHEN)
    , width(0)
    , dummy(0)
{
}
 
bool Hyphen::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&width, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
 
// toc mark(25)
TocMark::TocMark()
    : HBox(CH_TOC_MARK)
    , kind(0)
    , dummy(0)
{
}
 
 
bool TocMark::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&kind, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// index mark(26)
IndexMark::IndexMark()
    : HBox(CH_INDEX_MARK)
    , pgno(0)
    , dummy(0)
{
}
 
bool IndexMark::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&keyword1, 60);
    hwpf.Read2b(&keyword2, 60);
    hwpf.Read2b(&pgno, 1);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
// outline(28)
Outline::Outline()
    : HBox(CH_OUTLINE)
    , kind(0)
    , shape(0)
    , level(0)
    , dummy(0)
{
}
 
bool Outline::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&kind, 1);
    hwpf.Read1b(shape);
    hwpf.Read1b(level);
    hwpf.Read2b(number, 7);
    hwpf.Read2b(user_shape, 7);
    hwpf.Read2b(deco, 14);
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
 
/* Bundle of spaces (30)*/
KeepSpace::KeepSpace()
    : HBox(CH_KEEP_SPACE)
    , dummy(0)
{
}
 
 
bool KeepSpace::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
 
/* Fixed-width spaces (31) */
FixedSpace::FixedSpace()
    : HBox(CH_FIXED_SPACE)
    , dummy(0)
{
}
 
 
bool FixedSpace::Read(HWPFile & hwpf)
{
    hwpf.Read2b(&dummy, 1);
 
    if (hh != dummy){
        return hwpf.SetState(HWP_InvalidFileFormat);
    }
    return !hwpf.State();
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V668 There is no sense in testing the 'pArr' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: reserved, reserved2.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: reserved, info.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: reserved, info.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: reserved, info.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: compose.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: number, user_shape, deco.