1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * This file is part of the libqxp project.
4  *
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/.
8  */
9 
10 #include "QXPBlockParser.h"
11 
12 #include <librevenge-stream/librevenge-stream.h>
13 #include <algorithm>
14 #include <memory>
15 #include <vector>
16 #include <cstdlib>
17 
18 #include "QXPHeader.h"
19 
20 namespace libqxp
21 {
22 
23 using librevenge::RVNGInputStream;
24 using librevenge::RVNGStringStream;
25 using std::make_shared;
26 using std::vector;
27 
QXPBlockParser(const std::shared_ptr<RVNGInputStream> & input,const std::shared_ptr<QXPHeader> & header)28 QXPBlockParser::QXPBlockParser(const std::shared_ptr<RVNGInputStream> &input, const std::shared_ptr<QXPHeader> &header)
29   : m_input(input)
30   , m_header(header)
31   , be(header->isBigEndian())
32   , m_blockLength(256)
33 {
34 }
35 
getBlock(const uint32_t index)36 std::shared_ptr<RVNGInputStream> QXPBlockParser::getBlock(const uint32_t index)
37 {
38   seek(m_input, (index - 1) * m_blockLength);
39   auto block = readNBytes(m_input, m_blockLength);
40   return make_shared<RVNGStringStream>(block, m_blockLength);
41 }
42 
getChain(const uint32_t index)43 std::shared_ptr<RVNGInputStream> QXPBlockParser::getChain(const uint32_t index)
44 {
45   bool bigIdx = m_header->version() >= QXPVersion::QXP_31_MAC;
46 
47   vector<unsigned char> chain;
48   bool isBig = false;
49   uint32_t next = index;
50   while (next > 0)
51   {
52     seek(m_input, (next - 1) * m_blockLength);
53     const uint16_t count = isBig ? readU16(m_input, be) : 1;
54 
55     uint32_t len = (next - 1 + count) * m_blockLength - (bigIdx ? 4 : 2) - m_input->tell();
56     auto block = readNBytes(m_input, len);
57     std::copy(block, block + len, std::back_inserter(chain));
58 
59     const int32_t nextVal = bigIdx ? readS32(m_input, be) : readS16(m_input, be);
60     isBig = nextVal < 0;
61     next = abs(nextVal);
62   }
63   return make_shared<RVNGStringStream>(chain.data(), chain.size());
64 }
65 
66 }
67 
68 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
69