Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/BeagleWksDBParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cmath>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <set>
39
#include <sstream>
40
41
#include <librevenge/librevenge.h>
42
43
#include "MWAWCell.hxx"
44
#include "MWAWFontConverter.hxx"
45
#include "MWAWHeader.hxx"
46
#include "MWAWList.hxx"
47
#include "MWAWParagraph.hxx"
48
#include "MWAWPosition.hxx"
49
#include "MWAWPrinter.hxx"
50
#include "MWAWRSRCParser.hxx"
51
#include "MWAWSpreadsheetListener.hxx"
52
#include "MWAWSubDocument.hxx"
53
54
#include "BeagleWksStructManager.hxx"
55
56
#include "BeagleWksDBParser.hxx"
57
58
/** Internal: the structures of a BeagleWksDBParser */
59
namespace BeagleWksDBParserInternal
60
{
61
//! Internal: the cell of a BeagleWksDBParser
62
struct Cell final : public MWAWCell {
63
  //! the cell type
64
  enum Type { Text, Number, Date, Time, Picture, Formula, Memo, Unknown };
65
  //! constructor
66
  explicit Cell(MWAWVec2i pos=MWAWVec2i(0,0))
67
67.4k
    : MWAWCell()
68
67.4k
    , m_type(Unknown)
69
67.4k
    , m_name("")
70
67.4k
    , m_content()
71
67.4k
    , m_formula(-1)
72
67.4k
    , m_pictureId(-1)
73
67.4k
    , m_isEmpty(false)
74
67.4k
  {
75
67.4k
    setPosition(pos);
76
67.4k
  }
77
123k
  Cell(Cell const &)=default;
78
  //! destructor
79
  ~Cell() final;
80
  //! returns true if the field has no content
81
  bool empty() const
82
93.2k
  {
83
93.2k
    return m_content.empty() && (m_type!=Picture || m_pictureId<=0);
84
93.2k
  }
85
  //! the cell type
86
  Type m_type;
87
  //! the field name
88
  std::string m_name;
89
  //! the cell content
90
  MWAWCellContent m_content;
91
  //! the formula id
92
  int m_formula;
93
  //! picture id
94
  int m_pictureId;
95
  //! flag to know if the cell is empty
96
  bool m_isEmpty;
97
};
98
99
Cell::~Cell()
100
191k
{
101
191k
}
102
103
//! Internal: the spreadsheet of a BeagleWksDBParser
104
struct Database {
105
  //! constructor
106
  Database()
107
26.8k
    : m_numFields(0)
108
26.8k
    , m_fields()
109
26.8k
    , m_records()
110
26.8k
    , m_memos()
111
26.8k
    , m_name("Sheet0")
112
26.8k
  {
113
26.8k
  }
114
  //! convert the m_widthCols, m_heightRows in a vector of of point size
115
  static std::vector<float> convertInPoint(std::vector<int> const &list, float defSize)
116
0
  {
117
0
    size_t numElt = list.size();
118
0
    std::vector<float> res;
119
0
    res.resize(numElt);
120
0
    for (size_t i = 0; i < numElt; i++) {
121
0
      if (list[i] < 0) res[i] = defSize;
122
0
      else res[i] = float(list[i]);
123
0
    }
124
0
    return res;
125
0
  }
126
  //! update a field with the record data
127
  void updateWithContent(Cell &cell, MWAWVec2i const &pos, MWAWCellContent const &content) const;
128
  //! the number of rows
129
  int m_numFields;
130
  //! the list of fields
131
  std::vector<Cell> m_fields;
132
  //! the list of not empty cells (one list by row )
133
  std::vector<std::vector<MWAWCellContent> > m_records;
134
  /** the list of memo strings entry */
135
  std::vector<MWAWEntry> m_memos;
136
  //! the database name
137
  std::string m_name;
138
};
139
140
void Database::updateWithContent(Cell &cell, MWAWVec2i const &pos, MWAWCellContent const &content) const
141
93.2k
{
142
93.2k
  cell.setPosition(pos);
143
93.2k
  switch (cell.m_type) {
144
16.0k
  case Cell::Formula:
145
16.0k
    cell.m_content.m_contentType=MWAWCellContent::C_FORMULA;
146
16.0k
    break;
147
5.42k
  case Cell::Number:
148
34.1k
  case Cell::Date:
149
34.7k
  case Cell::Time:
150
48.1k
  case Cell::Text:
151
48.1k
    cell.m_content=content;
152
48.1k
    break;
153
5.78k
  case Cell::Memo: {
154
5.78k
    if (!content.isValueSet()) break;
155
1.52k
    auto id=int(0.1+content.m_value);
156
1.52k
    if (id<1 || id>static_cast<int>(m_memos.size())) {
157
1.52k
      MWAW_DEBUG_MSG(("BeagleWksDBParserInternal::Database::updateWithContent: can not retrieve the memo content\n"));
158
1.52k
      break;
159
1.52k
    }
160
0
    cell.m_content.m_contentType=MWAWCellContent::C_TEXT;
161
0
    cell.m_content.m_textEntry=m_memos[size_t(id-1)];
162
0
    break;
163
1.52k
  }
164
409
  case Cell::Picture:
165
409
    cell.m_pictureId=int(0.1+content.m_value);
166
409
    break;
167
#if !defined(__clang__)
168
  default:
169
#endif
170
22.9k
  case Cell::Unknown:
171
22.9k
    break;
172
93.2k
  }
173
93.2k
  auto const &format=cell.getFormat();
174
  // change the reference date from 1/1/1904 to 1/1/1900
175
93.2k
  if (format.m_format==MWAWCell::F_DATE && cell.m_content.isValueSet())
176
79
    cell.m_content.setValue(cell.m_content.m_value+1460.);
177
  // and try to update the 1D formula in 2D
178
93.2k
  auto &formula=cell.m_content.m_formula;
179
93.2k
  for (auto &instr : formula) {
180
0
    if (instr.m_type==MWAWCellContent::FormulaInstruction::F_Cell) {
181
0
      --instr.m_position[0][0];
182
0
      instr.m_position[0][1]=pos[1];
183
0
    }
184
0
    else if (instr.m_type==MWAWCellContent::FormulaInstruction::F_CellList) {
185
0
      --instr.m_position[0][0];
186
0
      --instr.m_position[1][0];
187
0
      instr.m_position[0][1]=instr.m_position[1][1]=pos[1];
188
0
    }
189
0
  }
190
93.2k
}
191
192
////////////////////////////////////////
193
//! Internal: the state of a BeagleWksDBParser
194
struct State {
195
  //! constructor
196
  State()
197
26.8k
    : m_databaseBegin(-1)
198
26.8k
    , m_database()
199
26.8k
    , m_typeEntryMap()
200
26.8k
    , m_actPage(0)
201
26.8k
    , m_numPages(0)
202
26.8k
    , m_headerHeight(0)
203
26.8k
    , m_footerHeight(0)
204
26.8k
  {
205
26.8k
  }
206
  /** the database begin position */
207
  long m_databaseBegin;
208
  /** the database */
209
  Database m_database;
210
  /** the type entry map */
211
  std::multimap<std::string, MWAWEntry> m_typeEntryMap;
212
  int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
213
214
  int m_headerHeight /** the header height if known */,
215
      m_footerHeight /** the footer height if known */;
216
};
217
218
////////////////////////////////////////
219
//! Internal: the subdocument of a BeagleWksDBParser
220
class SubDocument final : public MWAWSubDocument
221
{
222
public:
223
  SubDocument(BeagleWksDBParser &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry)
224
323
    : MWAWSubDocument(&pars, input, entry)
225
323
  {
226
323
  }
227
228
  //! destructor
229
0
  ~SubDocument() final {}
230
231
  //! operator!=
232
  bool operator!=(MWAWSubDocument const &doc) const final
233
0
  {
234
0
    return MWAWSubDocument::operator!=(doc);
235
0
  }
236
237
  //! the parser function
238
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
239
240
protected:
241
private:
242
  SubDocument(SubDocument const &orig) = delete;
243
  SubDocument &operator=(SubDocument const &orig) = delete;
244
};
245
246
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
247
323
{
248
323
  if (!listener.get()) {
249
0
    MWAW_DEBUG_MSG(("BeagleWksDBParserInternal::SubDocument::parse: no listener\n"));
250
0
    return;
251
0
  }
252
323
  auto *parser=dynamic_cast<BeagleWksDBParser *>(m_parser);
253
323
  if (!parser) {
254
0
    MWAW_DEBUG_MSG(("BeagleWksDBParserInternal::SubDocument::parse: can not find the parser\n"));
255
0
    return;
256
0
  }
257
323
  long pos = m_input->tell();
258
323
  listener->setFont(MWAWFont(3,12)); // fixme
259
323
  parser->sendText(m_zone, true);
260
323
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
261
323
}
262
263
}
264
265
266
////////////////////////////////////////////////////////////
267
// constructor/destructor, ...
268
////////////////////////////////////////////////////////////
269
BeagleWksDBParser::BeagleWksDBParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
270
12.5k
  : MWAWSpreadsheetParser(input, rsrcParser, header)
271
12.5k
  , m_state()
272
12.5k
  , m_structureManager()
273
12.5k
{
274
12.5k
  init();
275
12.5k
}
276
277
BeagleWksDBParser::~BeagleWksDBParser()
278
12.5k
{
279
12.5k
}
280
281
void BeagleWksDBParser::init()
282
12.5k
{
283
12.5k
  resetSpreadsheetListener();
284
12.5k
  setAsciiName("main-1");
285
286
12.5k
  m_state.reset(new BeagleWksDBParserInternal::State);
287
12.5k
  m_structureManager.reset(new BeagleWksStructManager(getParserState()));
288
289
  // reduce the margin (in case, the page is not defined)
290
12.5k
  getPageSpan().setMargins(0.1);
291
12.5k
}
292
293
MWAWInputStreamPtr BeagleWksDBParser::rsrcInput()
294
0
{
295
0
  return getRSRCParser()->getInput();
296
0
}
297
298
libmwaw::DebugFile &BeagleWksDBParser::rsrcAscii()
299
0
{
300
0
  return getRSRCParser()->ascii();
301
0
}
302
303
////////////////////////////////////////////////////////////
304
// position and height
305
////////////////////////////////////////////////////////////
306
MWAWVec2f BeagleWksDBParser::getPageLeftTop() const
307
0
{
308
0
  return MWAWVec2f(float(getPageSpan().getMarginLeft()),
309
0
                   float(getPageSpan().getMarginTop()+m_state->m_headerHeight/72.0));
310
0
}
311
312
////////////////////////////////////////////////////////////
313
// the parser
314
////////////////////////////////////////////////////////////
315
void BeagleWksDBParser::parse(librevenge::RVNGSpreadsheetInterface *docInterface)
316
1.69k
{
317
1.69k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
318
1.69k
  bool ok = false;
319
1.69k
  try {
320
    // create the asciiFile
321
1.69k
    ascii().setStream(getInput());
322
1.69k
    ascii().open(asciiName());
323
324
1.69k
    checkHeader(nullptr);
325
1.69k
    ok = createZones();
326
1.69k
    if (ok) {
327
927
      createDocument(docInterface);
328
927
      sendDatabase();
329
927
    }
330
1.69k
    ascii().reset();
331
1.69k
  }
332
1.69k
  catch (...) {
333
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::parse: exception catched when parsing\n"));
334
0
    ok = false;
335
0
  }
336
337
1.69k
  resetSpreadsheetListener();
338
1.69k
  if (!ok) throw(libmwaw::ParseException());
339
1.69k
}
340
341
////////////////////////////////////////////////////////////
342
// create the document
343
////////////////////////////////////////////////////////////
344
void BeagleWksDBParser::createDocument(librevenge::RVNGSpreadsheetInterface *documentInterface)
345
927
{
346
927
  if (!documentInterface) return;
347
927
  if (getSpreadsheetListener()) {
348
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::createDocument: listener already exist\n"));
349
0
    return;
350
0
  }
351
352
  // update the page
353
927
  m_state->m_actPage = 0;
354
355
  // create the page list
356
927
  int numPages = 1;
357
927
  m_state->m_numPages = numPages;
358
359
927
  MWAWEntry header, footer;
360
927
  m_structureManager->getHeaderFooterEntries(header,footer);
361
927
  std::vector<MWAWPageSpan> pageList;
362
927
  MWAWPageSpan ps(getPageSpan());
363
927
  if (header.valid()) {
364
161
    std::shared_ptr<BeagleWksDBParserInternal::SubDocument> subDoc
365
161
    (new BeagleWksDBParserInternal::SubDocument(*this, getInput(), header));
366
161
    MWAWHeaderFooter hf(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
367
161
    hf.m_subDocument=subDoc;
368
161
    ps.setHeaderFooter(hf);
369
161
  }
370
927
  if (footer.valid()) {
371
162
    std::shared_ptr<BeagleWksDBParserInternal::SubDocument> subDoc
372
162
    (new BeagleWksDBParserInternal::SubDocument(*this, getInput(), footer));
373
162
    MWAWHeaderFooter hf(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
374
162
    hf.m_subDocument=subDoc;
375
162
    ps.setHeaderFooter(hf);
376
162
  }
377
927
  ps.setPageSpan(numPages);
378
927
  pageList.push_back(ps);
379
380
927
  MWAWSpreadsheetListenerPtr listen(new MWAWSpreadsheetListener(*getParserState(), pageList, documentInterface));
381
927
  setSpreadsheetListener(listen);
382
927
  listen->startDocument();
383
927
}
384
385
386
////////////////////////////////////////////////////////////
387
//
388
// Intermediate level
389
//
390
////////////////////////////////////////////////////////////
391
bool BeagleWksDBParser::createZones()
392
1.69k
{
393
1.69k
  readRSRCZones();
394
1.69k
  MWAWInputStreamPtr input = getInput();
395
1.69k
  if (input->seek(66, librevenge::RVNG_SEEK_SET) || !readPrintInfo())
396
11
    return false;
397
1.68k
  long pos = input->tell();
398
1.68k
  if (!input->checkPosition(pos+70)) {
399
72
    MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: the file can not contains Zones\n"));
400
72
    return false;
401
72
  }
402
403
  // now read the list of zones
404
1.60k
  libmwaw::DebugStream f;
405
1.60k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
406
1.60k
  f << "Entries(Zones):";
407
12.4k
  for (int i=0; i<7; ++i) { // checkme: at least 2 zones, maybe 7
408
10.9k
    MWAWEntry entry;
409
10.9k
    entry.setBegin(input->readLong(4));
410
10.9k
    entry.setLength(input->readLong(4));
411
10.9k
    entry.setId(static_cast<int>(input->readLong(2)));
412
10.9k
    if (entry.length()==0) continue;
413
5.72k
    entry.setType(i==1?"Frame":"Unknown");
414
5.72k
    f << entry.type() << "[" << entry.id() << "]="
415
5.72k
      << std::hex << entry.begin() << "<->" << entry.end() << ",";
416
5.72k
    if (!entry.valid() || !input->checkPosition(entry.end())) {
417
5.11k
      f << "###";
418
5.11k
      if (i<2) {
419
62
        MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not read the header zone, stop\n"));
420
62
        ascii().addPos(pos);
421
62
        ascii().addNote(f.str().c_str());
422
62
        return false;
423
62
      }
424
5.05k
      MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not zones entry %d\n",i));
425
5.05k
      continue;
426
5.11k
    }
427
615
    m_state->m_typeEntryMap.insert
428
615
    (std::multimap<std::string, MWAWEntry>::value_type(entry.type(),entry));
429
615
  }
430
1.54k
  ascii().addPos(pos);
431
1.54k
  ascii().addNote(f.str().c_str());
432
433
  // now parse the different zones
434
1.54k
  auto it=m_state->m_typeEntryMap.find("FontNames");
435
1.54k
  if (it!=m_state->m_typeEntryMap.end())
436
1.54k
    m_structureManager->readFontNames(it->second);
437
1.54k
  it=m_state->m_typeEntryMap.find("Frame");
438
1.54k
  if (it!=m_state->m_typeEntryMap.end())
439
47
    m_structureManager->readFrame(it->second);
440
441
  // now parse the different zones
442
2.15k
  for (auto const &eIt : m_state->m_typeEntryMap) {
443
2.15k
    MWAWEntry const &entry=eIt.second;
444
2.15k
    if (entry.isParsed())
445
749
      continue;
446
1.40k
    f.str("");
447
1.40k
    f << "Entries(" << entry.type() << ")[" << entry.id() << "]:";
448
1.40k
    ascii().addPos(entry.begin());
449
1.40k
    ascii().addNote(f.str().c_str());
450
1.40k
    ascii().addPos(entry.end());
451
1.40k
    ascii().addNote("_");
452
1.40k
  }
453
454
1.54k
  input->seek(m_state->m_databaseBegin, librevenge::RVNG_SEEK_SET);
455
1.54k
  pos = input->tell();
456
1.54k
  if (!m_structureManager->readDocumentInfo())
457
1.15k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
458
1.54k
  pos = input->tell();
459
1.54k
  if (!m_structureManager->readDocumentPreferences())
460
1.26k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
461
1.54k
  if (!readDatabase())
462
1.14k
    return m_state->m_database.m_records.size()!=0;
463
402
  pos=input->tell();
464
402
  auto N=static_cast<int>(input->readULong(2));
465
402
  if (N==0) {
466
125
    ascii().addPos(pos);
467
125
    ascii().addNote("_");
468
125
  }
469
277
  else {
470
    // unsure about the parsing of this zone: find N=2+000602000d02
471
277
    f.str("");
472
277
    f << "Entries(UnknZone0):";
473
277
    if (!input->checkPosition(pos+2+3*N)) {
474
200
      MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not read UnkZone0\n"));
475
200
      f << "###";
476
200
      ascii().addPos(pos);
477
200
      ascii().addNote(f.str().c_str());
478
200
      return true;
479
200
    }
480
77
    f << "unkn0=[";
481
15.1k
    for (int i=0; i< N; ++i)
482
15.0k
      f << input->readLong(2) << ",";
483
77
    f << "],";
484
77
    f << "unkn1=[";
485
15.1k
    for (int i=0; i< N; ++i)
486
15.0k
      f << input->readLong(1) << ",";
487
77
    f << "],";
488
77
  }
489
202
  ascii().addPos(pos);
490
202
  ascii().addNote(f.str().c_str());
491
202
  pos=input->tell();
492
202
  N=static_cast<int>(input->readULong(2));
493
202
  if (N==0) {
494
153
    ascii().addPos(pos);
495
153
    ascii().addNote("_");
496
153
  }
497
49
  else {
498
49
    MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: find data in UnkZone1\n"));
499
49
    f.str("");
500
49
    f << "Entries(UnknZone1):###";
501
49
    ascii().addPos(pos);
502
49
    ascii().addNote(f.str().c_str());
503
49
    return true;
504
49
  }
505
506
153
  pos=input->tell();
507
153
  f.str("");
508
153
  f << "Entries(Memo):";
509
153
  auto dSz=static_cast<long>(input->readULong(2));
510
153
  long endPos=pos+2+dSz;
511
153
  N=static_cast<int>(input->readULong(2));
512
153
  if (dSz<2+2*long(N) || !input->checkPosition(endPos)) {
513
78
    MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: find data in UnkZone1\n"));
514
78
    f << "###";
515
78
    ascii().addPos(pos);
516
78
    ascii().addNote(f.str().c_str());
517
78
    return true;
518
78
  }
519
75
  ascii().addPos(pos);
520
75
  ascii().addNote(f.str().c_str());
521
3.12k
  for (int i=0; i<N; ++i) {
522
3.07k
    pos=input->tell();
523
3.07k
    f.str("");
524
3.07k
    f << "Memo-"<< i << ":";
525
3.07k
    auto val=static_cast<int>(input->readLong(1));
526
3.07k
    if (val) f << "f0=" << val << ",";
527
3.07k
    auto sSz=static_cast<int>(input->readULong(1));
528
3.07k
    if (pos+2+sSz>endPos) {
529
22
      MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not read a memo\n"));
530
22
      f << "###";
531
22
      ascii().addPos(pos);
532
22
      ascii().addNote(f.str().c_str());
533
22
      return true;
534
22
    }
535
3.05k
    MWAWEntry memo;
536
3.05k
    memo.setBegin(input->tell());
537
3.05k
    memo.setLength(sSz);
538
3.05k
    m_state->m_database.m_memos.push_back(memo);
539
3.05k
    std::string text("");
540
41.2k
    for (int c=0; c<sSz; ++c) text+=char(input->readULong(1));
541
3.05k
    f << text << ",";
542
3.05k
    ascii().addPos(pos);
543
3.05k
    ascii().addNote(f.str().c_str());
544
3.05k
  }
545
53
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
546
547
53
  pos=input->tell();
548
53
  f.str("");
549
53
  f << "Entries(UnknZone2):";
550
53
  dSz=long(input->readULong(2));
551
53
  endPos=pos+6+dSz;
552
53
  auto val=static_cast<int>(input->readULong(2));
553
53
  if ((dSz%2) || val!=0xeb || !input->checkPosition(endPos)) {
554
20
    MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not read zone2\n"));
555
20
    f << "###";
556
20
    ascii().addPos(pos);
557
20
    ascii().addNote(f.str().c_str());
558
20
    return true;
559
20
  }
560
33
  N=static_cast<int>(input->readULong(2));
561
33
  if (N) f << "N=" << N << ",";
562
33
  if (dSz==2*N) {
563
28
    f << "unkn=[";
564
28
    for (int i=0; i<N; ++i)
565
0
      f << input->readLong(2) << ",";
566
28
    f << "],";
567
28
  }
568
5
  else
569
5
    f << "###,";
570
33
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
571
33
  ascii().addPos(pos);
572
33
  ascii().addNote(f.str().c_str());
573
574
  /* now the formula zone */
575
33
  auto &fields=m_state->m_database.m_fields;
576
33
  int n=0;
577
129
  for (auto &field : fields) {
578
129
    ++n;
579
129
    if (field.m_type!=BeagleWksDBParserInternal::Cell::Formula)
580
123
      continue;
581
6
    pos=input->tell();
582
6
    f.str("");
583
6
    f << "Entries(Formula):";
584
6
    auto id=static_cast<int>(input->readLong(2));
585
6
    if (id!=n-1) f << "#id=" << id << ",";
586
6
    dSz=static_cast<int>(input->readULong(2));
587
6
    endPos=pos+4+dSz;
588
6
    if (dSz==0 || !input->checkPosition(pos+4+dSz)) {
589
3
      MWAW_DEBUG_MSG(("BeagleWksDBParser::createZones: can not read a formula\n"));
590
3
      f << "###";
591
3
      ascii().addPos(pos);
592
3
      ascii().addNote(f.str().c_str());
593
3
      return true;
594
3
    }
595
3
    std::vector<MWAWCellContent::FormulaInstruction> formula;
596
3
    std::string error("");
597
3
    if (m_structureManager->readFormula(endPos, MWAWVec2i(id,9), formula, error)) {
598
0
      field.m_content.m_formula = formula;
599
0
      field.m_content.m_contentType = MWAWCellContent::C_FORMULA;
600
0
    }
601
3
    else
602
3
      f << "###";
603
3
    for (auto const &fo : formula)
604
0
      f << fo;
605
3
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
606
3
    ascii().addPos(pos);
607
3
    ascii().addNote(f.str().c_str());
608
3
  }
609
  /*
610
    now find
611
    000000000001000100000000 or
612
    000200000003000100020000
613
   */
614
30
  ascii().addPos(input->tell());
615
30
  ascii().addNote("Entries(ZoneEnd)");
616
30
  return true;
617
33
}
618
619
bool BeagleWksDBParser::readRSRCZones()
620
1.69k
{
621
1.69k
  MWAWRSRCParserPtr rsrcParser = getRSRCParser();
622
1.69k
  if (!rsrcParser)
623
1.56k
    return true;
624
625
130
  auto const &entryMap = rsrcParser->getEntriesMap();
626
  // the 1 zone
627
130
  char const *zNames[] = {"wPos", "DMPF" };
628
390
  for (int z = 0; z < 2; ++z) {
629
260
    auto it = entryMap.lower_bound(zNames[z]);
630
304
    while (it != entryMap.end()) {
631
133
      if (it->first != zNames[z])
632
89
        break;
633
44
      MWAWEntry const &entry = it++->second;
634
44
      switch (z) {
635
44
      case 0: // 1001
636
44
        m_structureManager->readwPos(entry);
637
44
        break;
638
0
      case 1: // find in one file with id=4661 6a1f 4057
639
0
        m_structureManager->readFontStyle(entry);
640
0
        break;
641
      /* find also
642
         - edpt: see sendPicture
643
         - DMPP: the paragraph style
644
         - sect and alis: position?, alis=filesystem alias(dir, filename, path...)
645
      */
646
0
      default:
647
0
        break;
648
44
      }
649
44
    }
650
260
  }
651
130
  return true;
652
130
}
653
654
////////////////////////////////////////////////////////////
655
// read the print info
656
////////////////////////////////////////////////////////////
657
bool BeagleWksDBParser::readPrintInfo()
658
5.04k
{
659
5.04k
  MWAWInputStreamPtr input = getInput();
660
5.04k
  long pos = input->tell();
661
5.04k
  if (!input->checkPosition(pos+0x70))
662
106
    return false;
663
664
4.94k
  libmwaw::DebugStream f;
665
  // print info
666
4.94k
  libmwaw::PrinterInfo info;
667
4.94k
  if (!info.read(input)) return false;
668
4.90k
  f << "Entries(PrintInfo):"<< info;
669
670
4.90k
  MWAWVec2i paperSize = info.paper().size();
671
4.90k
  MWAWVec2i pageSize = info.page().size();
672
4.90k
  if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
673
4.83k
      paperSize.x() <= 0 || paperSize.y() <= 0) return false;
674
675
  // define margin from print info
676
4.76k
  MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
677
4.76k
  MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
678
679
  // move margin left | top
680
4.76k
  int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
681
4.76k
  int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
682
4.76k
  lTopMargin -= MWAWVec2i(decalX, decalY);
683
4.76k
  rBotMargin += MWAWVec2i(decalX, decalY);
684
685
  // decrease right | bottom
686
4.76k
  int rightMarg = rBotMargin.x() -10;
687
4.76k
  if (rightMarg < 0) rightMarg=0;
688
4.76k
  int botMarg = rBotMargin.y() -50;
689
4.76k
  if (botMarg < 0) botMarg=0;
690
691
4.76k
  getPageSpan().setMarginTop(lTopMargin.y()/72.0);
692
4.76k
  getPageSpan().setMarginBottom(botMarg/72.0);
693
4.76k
  getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
694
4.76k
  getPageSpan().setMarginRight(rightMarg/72.0);
695
4.76k
  getPageSpan().setFormLength(paperSize.y()/72.);
696
4.76k
  getPageSpan().setFormWidth(paperSize.x()/72.);
697
698
4.76k
  ascii().addPos(pos);
699
4.76k
  ascii().addNote(f.str().c_str());
700
4.76k
  input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
701
4.76k
  if (long(input->tell()) != pos+0x78) {
702
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readPrintInfo: file is too short\n"));
703
0
    return false;
704
0
  }
705
4.76k
  ascii().addPos(input->tell());
706
707
4.76k
  return true;
708
4.76k
}
709
710
////////////////////////////////////////////////////////////
711
// database
712
////////////////////////////////////////////////////////////
713
bool BeagleWksDBParser::readDatabase()
714
1.54k
{
715
1.54k
  if (!readFields() || !readLayouts()) return false;
716
717
1.00k
  MWAWInputStreamPtr &input= getInput();
718
1.00k
  long pos=input->tell();
719
1.00k
  if (!input->checkPosition(pos+6)) {
720
4
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readDatabase: can not find the database header\n"));
721
4
    return false;
722
4
  }
723
998
  libmwaw::DebugStream f;
724
998
  f << "Entries(DbRow):";
725
998
  int val;
726
2.99k
  for (int i=0; i<2; ++i) { // f0=0|1
727
1.99k
    val =static_cast<int>(input->readLong(2));
728
1.99k
    if (val) f << "f" << i << "=" << val << ",";
729
1.99k
  }
730
998
  val =static_cast<int>(input->readLong(2));
731
998
  if (val!=7) f << "f2=" << val << ",";
732
998
  auto N=static_cast<int>(input->readLong(2));
733
998
  f << "N=" << N << ",";
734
998
  val =static_cast<int>(input->readLong(2));
735
998
  if (val) f << "f3=" << val << ",";
736
998
  ascii().addPos(pos);
737
998
  ascii().addNote(f.str().c_str());
738
739
10.3k
  for (int i=0; i<=N; ++i) {
740
9.83k
    if (!readRow()) return false;
741
9.83k
  }
742
743
469
  pos=input->tell();
744
469
  f.str("");
745
469
  f << "Entries(DbFld):";
746
469
  val =static_cast<int>(input->readLong(2));
747
469
  if (val) f << "f0=" << val << ",";
748
469
  N=static_cast<int>(input->readULong(2));
749
469
  f << "N=" << N << ",";
750
469
  val =static_cast<int>(input->readLong(2));
751
469
  if (val) f << "f1=" << val << ",";
752
469
  auto dSz =static_cast<int>(input->readULong(2));
753
469
  f << "dSz=" << dSz << ",";
754
469
  if (dSz<14 || dSz>(input->size()-pos-8)/(N+1)) {
755
67
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readDatabase: can not find the database field format\n"));
756
67
    f << "###";
757
67
    ascii().addPos(pos);
758
67
    ascii().addNote(f.str().c_str());
759
67
    return false;
760
67
  }
761
402
  ascii().addPos(pos);
762
402
  ascii().addNote(f.str().c_str());
763
764
402
  auto &database=m_state->m_database;
765
402
  size_t numFields=database.m_fields.size();
766
402
  if (N+1>static_cast<int>(numFields)) {
767
365
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readDatabase: the number of field seems too small, must increase them\n"));
768
365
    database.m_fields.resize(size_t(N+1));
769
365
  }
770
402
  std::string extra("");
771
54.7k
  for (int i=0; i<=N; ++i) {
772
54.3k
    pos=input->tell();
773
54.3k
    f.str("");
774
54.3k
    f << "DbFld" << i << ":";
775
54.3k
    val=static_cast<int>(input->readULong(2));
776
54.3k
    if (val!=1) f << "f0=" << val << ",";
777
54.3k
    val=static_cast<int>(input->readLong(2));
778
54.3k
    if (val!=0x4b) f << "f1=" << val << ",";
779
    // checkme: maybe we must use the read id here...
780
54.3k
    auto &field=database.m_fields[size_t(i)];
781
54.3k
    if (readFormat(field, extra)) {
782
54.3k
      f << extra << ",";
783
54.3k
      if (dSz>14) { // find also dSz=18 which add c0000034 here
784
49.2k
        ascii().addDelimiter(input->tell(),'|');
785
49.2k
        input->seek(pos+dSz-2, librevenge::RVNG_SEEK_SET);
786
49.2k
        ascii().addDelimiter(input->tell(),'|');
787
49.2k
      }
788
54.3k
      val=static_cast<int>(input->readLong(2));
789
54.3k
      if (val!=i) f << "#id=" << val << ",";
790
54.3k
    }
791
54.3k
    input->seek(pos+dSz, librevenge::RVNG_SEEK_SET);
792
54.3k
    ascii().addPos(pos);
793
54.3k
    ascii().addNote(f.str().c_str());
794
54.3k
  }
795
402
  return true;
796
469
}
797
798
/* read a cell format
799
800
   \note: this function is very simillar to BeagleWksSSParser readCellSheet, maybe, we can merge them
801
 */
802
bool BeagleWksDBParser::readFormat(MWAWCell &cell, std::string &extra)
803
56.0k
{
804
56.0k
  MWAWInputStreamPtr &input= getInput();
805
56.0k
  long pos=input->tell();
806
56.0k
  if (!input->checkPosition(pos+8)) {
807
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readFormat: the zone is too short\n"));
808
0
    return false;
809
0
  }
810
56.0k
  libmwaw::DebugStream f;
811
56.0k
  MWAWFont font;
812
56.0k
  MWAWCell::Format format;
813
56.0k
  auto val=static_cast<int>(input->readULong(1));
814
56.0k
  if (val) f << "f0=" << std::hex << val << std::dec << ",";
815
56.0k
  val=static_cast<int>(input->readLong(1));
816
56.0k
  if (val>0)
817
27.0k
    font.setSize(float(val));
818
56.0k
  val=static_cast<int>(input->readLong(2));
819
56.0k
  if (val>=0)
820
42.8k
    font.setId(val);
821
56.0k
  auto flag=static_cast<int>(input->readULong(1));
822
56.0k
  uint32_t flags=0;
823
56.0k
  if (flag&0x8) flags |= MWAWFont::boldBit;
824
56.0k
  if (flag&0x10) flags |= MWAWFont::italicBit;
825
56.0k
  if (flag&0x20) font.setUnderlineStyle(MWAWFont::Line::Simple);
826
56.0k
  if (flag&0x40) flags |= MWAWFont::embossBit;
827
56.0k
  if (flag&0x80) flags |= MWAWFont::shadowBit;
828
56.0k
  font.setFlags(flags);
829
56.0k
  f << font.getDebugString(getParserState()->m_fontConverter);
830
56.0k
  if (flag&7) f << "flags=" << (flag&7) << ",";
831
832
56.0k
  auto form=static_cast<int>(input->readULong(1));
833
56.0k
  if (form) {
834
39.2k
    if (form & 0x10)
835
14.9k
      format.m_thousandHasSeparator=true;
836
39.2k
    switch (form>>5) {
837
11.7k
    case 0: // generic (or picture, memo, etc)
838
11.7k
      break;
839
6.36k
    case 1:
840
6.36k
      format.m_format=MWAWCell::F_NUMBER;
841
6.36k
      format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY;
842
6.36k
      break;
843
3.93k
    case 2:
844
3.93k
      format.m_format=MWAWCell::F_NUMBER;
845
3.93k
      format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT;
846
3.93k
      break;
847
3.57k
    case 3:
848
3.57k
      format.m_format=MWAWCell::F_NUMBER;
849
3.57k
      format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC;
850
3.57k
      break;
851
2.88k
    case 4:
852
2.88k
      format.m_format=MWAWCell::F_NUMBER;
853
2.88k
      format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
854
2.88k
      break;
855
1.99k
    case 5:
856
1.99k
      format.m_format=MWAWCell::F_DATE;
857
1.99k
      format.m_DTFormat="%m/%d/%y";
858
1.99k
      break;
859
3.56k
    case 6:
860
3.56k
      switch (form & 0x7) {
861
848
      case 0:
862
848
        format.m_format=MWAWCell::F_DATE;
863
848
        format.m_DTFormat="%b %d, %Y";
864
848
        break;
865
347
      case 1:
866
347
        format.m_format=MWAWCell::F_DATE;
867
347
        format.m_DTFormat="%B %d, %Y";
868
347
        break;
869
342
      case 2:
870
342
        format.m_format=MWAWCell::F_DATE;
871
342
        format.m_DTFormat="%a, %b %d, %Y";
872
342
        break;
873
335
      case 3:
874
335
        format.m_format=MWAWCell::F_DATE;
875
335
        format.m_DTFormat="%A, %B %d, %Y";
876
335
        break;
877
481
      case 4:
878
481
        format.m_format=MWAWCell::F_TIME;
879
481
        format.m_DTFormat="%I:%M %p";
880
481
        break;
881
574
      case 5:
882
574
        format.m_format=MWAWCell::F_TIME;
883
574
        format.m_DTFormat="%I:%M:%S %p";
884
574
        break;
885
401
      case 6:
886
401
        format.m_format=MWAWCell::F_TIME;
887
401
        format.m_DTFormat="%H:%M";
888
401
        break;
889
235
      case 7:
890
235
        format.m_format=MWAWCell::F_TIME;
891
235
        format.m_DTFormat="%H:%M:%S";
892
235
        break;
893
0
      default:
894
0
        break;
895
3.56k
      }
896
3.56k
      form &= 0x8;
897
3.56k
      break;
898
5.17k
    default:
899
5.17k
      f << "#form=7:";
900
5.17k
      break;
901
39.2k
    }
902
39.2k
    if (form & 0xf)
903
34.1k
      format.m_digits=(form & 0xf);
904
39.2k
    f << format;
905
39.2k
  }
906
907
56.0k
  val=static_cast<int>(input->readULong(1));
908
56.0k
  if (val&0xF0) f << "col?="<<std::hex << (val>>4) << std::dec << ",";
909
56.0k
  if (val&0xf) f << "bord?="<<std::hex << (val&0xF) << std::dec << ",";
910
911
56.0k
  val=static_cast<int>(input->readULong(1));
912
56.0k
  switch ((val>>5)&7) {
913
27.4k
  case 0:
914
27.4k
    cell.setHAlignment(MWAWCell::HALIGN_LEFT);
915
27.4k
    f << "left,";
916
27.4k
    break;
917
6.46k
  case 1:
918
6.46k
    cell.setHAlignment(MWAWCell::HALIGN_RIGHT);
919
6.46k
    f << "right,";
920
6.46k
    break;
921
3.95k
  case 2:
922
3.95k
    cell.setHAlignment(MWAWCell::HALIGN_CENTER);
923
3.95k
    f << "center,";
924
3.95k
    break;
925
4.88k
  case 3: // default
926
4.88k
    break;
927
2.74k
  case 4:
928
2.74k
    cell.setHAlignment(MWAWCell::HALIGN_LEFT);
929
2.74k
    f << "filled,";
930
2.74k
    break;
931
10.5k
  default:
932
10.5k
    f << "#align=" << ((val>>5)&7) << ",";
933
10.5k
    break;
934
56.0k
  }
935
56.0k
  cell.setFormat(format);
936
  // checkme, this flags seem important, but I am not sure of their meanings
937
56.0k
  if (val&0x10)
938
16.6k
    cell.setFont(font);
939
56.0k
  val &= 0xF;
940
56.0k
  if (val!=0x3) f << "flags2=" << std::hex << val << std::dec << ",";
941
56.0k
  extra=f.str();
942
56.0k
  return true;
943
56.0k
}
944
945
946
////////////////////////////////////////////////////////////
947
// read the row data
948
////////////////////////////////////////////////////////////
949
bool BeagleWksDBParser::readRow()
950
9.83k
{
951
9.83k
  MWAWInputStreamPtr &input= getInput();
952
9.83k
  long pos=input->tell();
953
9.83k
  libmwaw::DebugStream f;
954
955
9.83k
  auto id=static_cast<int>(input->readLong(2));
956
9.83k
  f << "DbRow" << id << ":";
957
9.83k
  auto val=static_cast<int>(input->readLong(2));
958
9.83k
  if (val) f << "f0=" << val << ",";
959
9.83k
  auto dSz=long(input->readULong(2));
960
9.83k
  long endPos=pos+6+dSz;
961
9.83k
  if (dSz<18 || !input->checkPosition(endPos)) {
962
529
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readRow: can not find the database row %d\n", id));
963
529
    f << "###";
964
529
    ascii().addPos(pos);
965
529
    ascii().addNote(f.str().c_str());
966
529
    return false;
967
529
  }
968
9.30k
  val=static_cast<int>(input->readLong(2)); // 0|78|86
969
9.30k
  if (val) f << "f1=" << val << ",";
970
9.30k
  val=static_cast<int>(input->readLong(2));
971
9.30k
  if (val!=-1) f << "f2=" << val << ",";
972
9.30k
  f << "fl?=[" << std::hex;
973
46.5k
  for (int i=0; i<4; ++i) {
974
37.2k
    val=static_cast<int>(input->readULong(2));
975
37.2k
    if (val) f << val << ",";
976
2.11k
    else f << "_,";
977
37.2k
  }
978
9.30k
  f << std::dec << "],";
979
  // now a format
980
9.30k
  f << "fId=" << input->readULong(2) << ",";
981
9.30k
  f << "fSz=" << input->readULong(2) << ",";
982
9.30k
  val=static_cast<int>(input->readULong(2));
983
9.30k
  if (val!=dSz) f << "#dSz1=" << val << ",";
984
985
9.30k
  ascii().addPos(pos);
986
9.30k
  ascii().addNote(f.str().c_str());
987
988
9.30k
  auto &database=m_state->m_database;
989
9.30k
  database.m_records.resize(database.m_records.size()+1);
990
9.30k
  auto &records=database.m_records.back();
991
9.30k
  int fd=0;
992
94.3k
  for (auto const &field : database.m_fields) {
993
94.3k
    pos=input->tell();
994
94.3k
    if (pos>=endPos) break;
995
94.0k
    f.str("");
996
94.0k
    f << "DbRow" << id << "-" << fd++ << ":";
997
94.0k
    auto fSz=static_cast<int>(input->readULong(1));
998
94.0k
    if (fSz==0xFF) {
999
433
      ascii().addPos(pos);
1000
433
      ascii().addNote("_");
1001
433
      break;
1002
433
    }
1003
93.5k
    if (pos+fSz+2>endPos) {
1004
308
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1005
308
      MWAW_DEBUG_MSG(("BeagleWksDBParser::readRow: file size seems bad\n"));
1006
308
      break;
1007
308
    }
1008
93.2k
    val=static_cast<int>(input->readULong(1));
1009
93.2k
    if (val!=0x20) f << "fl=" << std::hex << val << std::dec << ",";
1010
93.2k
    MWAWCellContent content;
1011
93.2k
    if (fSz && fSz<8) {
1012
53.2k
      MWAW_DEBUG_MSG(("BeagleWksDBParser::readRow: find some very short field\n"));
1013
53.2k
      f << "###sz=" << fSz << ",";
1014
53.2k
    }
1015
40.0k
    else if (fSz) {
1016
177k
      for (int i=0; i<4; ++i) {
1017
141k
        val=static_cast<int>(input->readULong(2));
1018
141k
        if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1019
141k
      }
1020
35.4k
      switch (field.m_type) {
1021
4.30k
      case BeagleWksDBParserInternal::Cell::Formula:
1022
4.30k
        if (fSz>20) break;
1023
3.76k
        val=static_cast<int>(input->readULong(2));
1024
3.76k
        if (val) f << "g0=" << std::hex << val << std::dec << ",";
1025
3.76k
        MWAW_FALLTHROUGH;
1026
5.30k
      case BeagleWksDBParserInternal::Cell::Memo: // memoId
1027
5.43k
      case BeagleWksDBParserInternal::Cell::Picture: // pictId
1028
7.89k
      case BeagleWksDBParserInternal::Cell::Number:
1029
18.0k
      case BeagleWksDBParserInternal::Cell::Date:
1030
18.2k
      case BeagleWksDBParserInternal::Cell::Time: {
1031
        // will be changed by sendDatabase for memo, formula, ...
1032
18.2k
        content.m_contentType=MWAWCellContent::C_NUMBER;
1033
18.2k
        if (input->tell()+10>endPos) {
1034
15
          MWAW_DEBUG_MSG(("BeagleWksDBParser::readRow: can not read some field\n"));
1035
15
          f << "###";
1036
15
          break;
1037
15
        }
1038
18.2k
        double value;
1039
18.2k
        bool isNan;
1040
18.2k
        if (!input->readDouble10(value,isNan)) {
1041
89
          f << "#" << value << ",";
1042
89
          break;
1043
89
        }
1044
18.1k
        content.setValue(value);
1045
18.1k
        f << value << ",";
1046
18.1k
        break;
1047
18.2k
      }
1048
9.64k
      case BeagleWksDBParserInternal::Cell::Text: {
1049
9.64k
        content.m_contentType=MWAWCellContent::C_TEXT;
1050
9.64k
        content.m_textEntry.setBegin(input->tell());
1051
9.64k
        content.m_textEntry.setEnd(pos+fSz+2);
1052
9.64k
        std::string text("");
1053
211k
        while (input->tell()<pos+fSz+2) text+=char(input->readULong(1));
1054
9.64k
        f << text << ",";
1055
9.64k
      }
1056
9.64k
      break;
1057
7.00k
      case BeagleWksDBParserInternal::Cell::Unknown:
1058
#if !defined(__clang__)
1059
      default:
1060
#endif
1061
7.00k
        f << "type=" << static_cast<int>(field.m_type) << ",";
1062
7.00k
        break;
1063
35.4k
      }
1064
35.4k
    }
1065
93.2k
    records.push_back(content);
1066
93.2k
    if ((fSz%2)) ++fSz;
1067
93.2k
    input->seek(pos+fSz+2, librevenge::RVNG_SEEK_SET);
1068
93.2k
    ascii().addPos(pos);
1069
93.2k
    ascii().addNote(f.str().c_str());
1070
93.2k
  }
1071
1072
9.30k
  pos=input->tell();
1073
9.30k
  if (pos!=endPos) {
1074
8.91k
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readRow: find some extra data\n"));
1075
8.91k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1076
8.91k
    ascii().addPos(pos);
1077
8.91k
    ascii().addNote("DbRow:#end");
1078
8.91k
  }
1079
9.30k
  return true;
1080
9.30k
}
1081
1082
////////////////////////////////////////////////////////////
1083
// read the fields
1084
////////////////////////////////////////////////////////////
1085
bool BeagleWksDBParser::readFields()
1086
1.54k
{
1087
1.54k
  MWAWInputStreamPtr &input= getInput();
1088
1.54k
  auto &database=m_state->m_database;
1089
1.54k
  long pos=input->tell();
1090
1.54k
  if (!input->checkPosition(pos+6)) {
1091
12
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readFields: can not find the field zone\n"));
1092
12
    return false;
1093
12
  }
1094
1.53k
  libmwaw::DebugStream f;
1095
1.53k
  f << "Entries(Field):";
1096
1.53k
  auto val=static_cast<int>(input->readLong(2));
1097
1.53k
  if (val) f << "f0=" << val << ",";
1098
1.53k
  val=static_cast<int>(input->readLong(2));
1099
1.53k
  if (val!=0x2c) // may a type
1100
1.40k
    f << "f1=" << val << ",";
1101
1.53k
  database.m_numFields=static_cast<int>(input->readULong(2));
1102
1.53k
  f << "num[fields]=" << database.m_numFields << ",";
1103
1.53k
  if (!input->checkPosition(pos+database.m_numFields*64)) {
1104
103
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readFields: can not find the fields zone\n"));
1105
103
    f << "###";
1106
103
    ascii().addPos(pos);
1107
103
    ascii().addNote(f.str().c_str());
1108
103
    return false;
1109
103
  }
1110
1.43k
  ascii().addPos(pos);
1111
1.43k
  ascii().addNote(f.str().c_str());
1112
1113
14.3k
  for (int fld=0; fld<database.m_numFields; ++fld) {
1114
13.1k
    pos=input->tell();
1115
13.1k
    f.str("");
1116
13.1k
    f << "Field-" << fld << ":";
1117
13.1k
    BeagleWksDBParserInternal::Cell field;
1118
13.1k
    auto dSz=long(input->readULong(2));
1119
13.1k
    long endPos=pos+4+dSz;
1120
13.1k
    if (dSz<0x3c || !input->checkPosition(endPos)) {
1121
225
      MWAW_DEBUG_MSG(("BeagleWksDBParser::readFields: can not read a field\n"));
1122
225
      f << "###";
1123
225
      ascii().addPos(pos);
1124
225
      ascii().addNote(f.str().c_str());
1125
225
      return false;
1126
225
    }
1127
12.9k
    auto id=static_cast<int>(input->readLong(2));
1128
12.9k
    if (id) f << "id=" << id << ",";
1129
12.9k
    auto sSz=static_cast<int>(input->readULong(1));
1130
12.9k
    if (sSz+1>dSz) {
1131
6
      MWAW_DEBUG_MSG(("BeagleWksDBParser::readFields: can not read a field\n"));
1132
6
      f << "###";
1133
6
      ascii().addPos(pos);
1134
6
      ascii().addNote(f.str().c_str());
1135
6
      return false;
1136
6
    }
1137
144k
    for (int i=0; i<sSz; ++i) field.m_name += char(input->readULong(1));
1138
12.9k
    f << "\"" << field.m_name << "\",";
1139
12.9k
    ascii().addDelimiter(input->tell(),'|');
1140
12.9k
    input->seek(endPos-10, librevenge::RVNG_SEEK_SET);
1141
12.9k
    ascii().addDelimiter(input->tell(),'|');
1142
1143
12.9k
    MWAWCell::Format format;
1144
12.9k
    auto &content=field.m_content;
1145
12.9k
    auto type=static_cast<int>(input->readLong(1));
1146
12.9k
    switch (type) {
1147
1.04k
    case 0:
1148
1.04k
      field.m_type = BeagleWksDBParserInternal::Cell::Text;
1149
1.04k
      content.m_contentType=MWAWCellContent::C_TEXT;
1150
1.04k
      f << "text,";
1151
1.04k
      break;
1152
1.81k
    case 1:
1153
1.81k
      field.m_type = BeagleWksDBParserInternal::Cell::Number;
1154
1.81k
      content.m_contentType=MWAWCellContent::C_NUMBER;
1155
1.81k
      f << "number,";
1156
1.81k
      break;
1157
2.81k
    case 2:
1158
2.81k
      field.m_type = BeagleWksDBParserInternal::Cell::Date;
1159
2.81k
      content.m_contentType=MWAWCellContent::C_NUMBER;
1160
2.81k
      f << "date,";
1161
2.81k
      break;
1162
234
    case 3:
1163
234
      field.m_type = BeagleWksDBParserInternal::Cell::Time;
1164
234
      content.m_contentType=MWAWCellContent::C_NUMBER;
1165
234
      f << "time,";
1166
234
      break;
1167
1.70k
    case 4:
1168
1.70k
      field.m_type = BeagleWksDBParserInternal::Cell::Picture;
1169
1.70k
      f << "picture,";
1170
1.70k
      break;
1171
1.42k
    case 5:
1172
1.42k
      field.m_type = BeagleWksDBParserInternal::Cell::Formula;
1173
1.42k
      content.m_contentType=MWAWCellContent::C_FORMULA;
1174
1.42k
      f << "formula,";
1175
1.42k
      break;
1176
1.22k
    case 6:
1177
1.22k
      field.m_type = BeagleWksDBParserInternal::Cell::Memo;
1178
1.22k
      content.m_contentType=MWAWCellContent::C_TEXT;
1179
1.22k
      f << "memo,";
1180
1.22k
      break;
1181
2.65k
    default:
1182
2.65k
      f << "#type=" << type << ",";
1183
2.65k
      break;
1184
12.9k
    }
1185
12.9k
    f << "form?=" << std::hex << input->readULong(1) << std::dec << ",";
1186
12.9k
    f << "id2=" << std::hex << input->readULong(4) << std::dec << ",";
1187
12.9k
    val=static_cast<int>(input->readLong(2)); // 0|-1
1188
12.9k
    if (val!=-1) f << "g0=" << val << ",";
1189
12.9k
    f << "g1=" << input->readLong(2) << ",";
1190
12.9k
    database.m_fields.push_back(field);
1191
1192
12.9k
    ascii().addPos(pos);
1193
12.9k
    ascii().addNote(f.str().c_str());
1194
12.9k
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
1195
12.9k
  }
1196
1.20k
  return true;
1197
1.43k
}
1198
1199
////////////////////////////////////////////////////////////
1200
// read the layouts
1201
////////////////////////////////////////////////////////////
1202
bool BeagleWksDBParser::readLayouts()
1203
1.20k
{
1204
1.20k
  MWAWInputStreamPtr &input= getInput();
1205
1.20k
  long pos=input->tell();
1206
1.20k
  if (!input->checkPosition(pos+6)) {
1207
12
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can not find the layout zone\n"));
1208
12
    return false;
1209
12
  }
1210
1.18k
  libmwaw::DebugStream f;
1211
1.18k
  f << "Entries(Layout):";
1212
1.18k
  auto val=static_cast<int>(input->readLong(2));
1213
1.18k
  if (val) f << "f0=" << val << ",";
1214
1.18k
  val=static_cast<int>(input->readLong(2));
1215
1.18k
  if (val!=0x29) // may a type
1216
1.07k
    f << "f1=" << val << ",";
1217
1.18k
  auto numLayouts=static_cast<int>(input->readULong(2));
1218
1.18k
  f << "num[layout]=" << numLayouts << ",";
1219
1.18k
  ascii().addPos(pos);
1220
1.18k
  ascii().addNote(f.str().c_str());
1221
1222
1.33k
  for (int layout=0; layout<numLayouts; ++layout) {
1223
329
    if (!readLayout(layout)) return false;
1224
329
  }
1225
1.00k
  return true;
1226
1.18k
}
1227
1228
bool BeagleWksDBParser::readLayout(int id)
1229
329
{
1230
329
  MWAWInputStreamPtr &input= getInput();
1231
329
  libmwaw::DebugStream f;
1232
329
  f << "Layout-" << id << "[A]:";
1233
1234
329
  long pos=input->tell();
1235
329
  auto readId=static_cast<int>(input->readULong(1));
1236
329
  auto dSz=long(input->readULong(2));
1237
329
  long endPos=pos+1+dSz;
1238
329
  if (dSz<100 || !input->checkPosition(endPos)) {
1239
60
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can find a layout\n"));
1240
60
    f << "###";
1241
60
    ascii().addPos(pos);
1242
60
    ascii().addNote(f.str().c_str());
1243
60
    return false;
1244
60
  }
1245
269
  if (readId!=id) f << "#id=" << readId << ",";
1246
269
  auto val=static_cast<int>(input->readLong(2));
1247
269
  if (val) f << "f0=" << val << ",";
1248
269
  val=static_cast<int>(input->readULong(1));
1249
269
  if (val!=readId) f << "#id1=" << val << ",";
1250
269
  auto sSz=static_cast<int>(input->readULong(1));
1251
269
  if (sSz>30) {
1252
7
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can find layout string\n"));
1253
7
    f << "###sSz=" << sSz << ",";
1254
7
    ascii().addPos(pos);
1255
7
    ascii().addNote(f.str().c_str());
1256
7
    return false;
1257
7
  }
1258
262
  std::string name("");
1259
1.88k
  for (int i=0; i<sSz; ++i) name+=char(input->readULong(1));
1260
262
  f << name << ",";
1261
262
  input->seek(pos+37, librevenge::RVNG_SEEK_SET);
1262
262
  f << "ids=[" << std::hex;
1263
1.04k
  for (int i=0; i<3; ++i) f << input->readULong(4) << ",";
1264
262
  f << std::dec << "],";
1265
262
  val=static_cast<int>(input->readLong(2)); // small number
1266
262
  f << "N=" << val << ",";
1267
1.83k
  for (int i=0; i<6; ++i) { // f4=0|78, f5=0|68
1268
1.57k
    static int const expected[]= {0x100, 0, 0, 0, 0, 0xffff };
1269
1.57k
    val = static_cast<int>(input->readULong(2));
1270
1.57k
    if (val!=expected[i])
1271
552
      f << "f" << i+2 << "=" << std::hex << val << std::dec << ",";
1272
1.57k
  }
1273
262
  f << "g0=" << std::hex << input->readULong(4) << std::dec << ",";
1274
262
  f << "id2s=[" << std::hex;
1275
1.31k
  for (int i=0; i<4; ++i) {
1276
1.04k
    val=static_cast<int>(input->readULong(i==2 ? 2 : 4));
1277
1.04k
    if (val)
1278
870
      f << val << ",";
1279
178
    else
1280
178
      f << "_,";
1281
1.04k
  }
1282
262
  f << std::dec << "],";
1283
262
  ascii().addPos(pos);
1284
262
  ascii().addNote(f.str().c_str());
1285
1286
262
  pos=input->tell();
1287
262
  f.str("");
1288
262
  f << "Layout-" << id << "[B]:";
1289
262
  double margins[4];
1290
262
  f << "margins=[";
1291
1.04k
  for (double &margin : margins) {
1292
1.04k
    margin=double(input->readLong(4))/72.;
1293
1.04k
    f << margin << ",";
1294
1.04k
  }
1295
262
  f << "],";
1296
1.04k
  for (int i=0; i<3; ++i) {
1297
786
    val=static_cast<int>(input->readLong(2));
1298
786
    if (val) f << "f" << i << "=" << val << ",";
1299
786
  }
1300
262
  f << "id=" << std::hex << input->readULong(4) << std::dec << ",";
1301
262
  ascii().addDelimiter(input->tell(),'|');
1302
262
  ascii().addPos(pos);
1303
262
  ascii().addNote(f.str().c_str());
1304
1305
262
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1306
262
  pos=input->tell();
1307
262
  f.str("");
1308
262
  f << "Layout-" << id << "[C]:";
1309
2.35k
  for (int i=0; i<8; i++) {
1310
2.09k
    val=static_cast<int>(input->readLong(1));
1311
2.09k
    if (val==1) f << "fl" << i << ",";
1312
1.43k
    else if (val) f << "fl" << i << "=" << val << ",";
1313
2.09k
  }
1314
262
  ascii().addPos(pos);
1315
262
  ascii().addNote(f.str().c_str());
1316
  //--- now some big unknown zones
1317
262
  pos=input->tell();
1318
262
  f.str("");
1319
262
  f << "Layout-" << id << "[C0]:";
1320
262
  ascii().addPos(pos);
1321
262
  ascii().addNote(f.str().c_str());
1322
262
  input->seek(pos+244, librevenge::RVNG_SEEK_SET);
1323
1324
262
  pos=input->tell();
1325
262
  f.str("");
1326
262
  f << "Layout-" << id << "[C1]:";
1327
262
  ascii().addPos(pos);
1328
262
  ascii().addNote(f.str().c_str());
1329
262
  input->seek(pos+178, librevenge::RVNG_SEEK_SET);
1330
1331
  /* in some positions there seems be some blocks with size 12
1332
     so let's try this decomposition ( which clearly does not works )..
1333
   */
1334
23.0k
  for (int i=0; i<87; ++i) {
1335
22.7k
    pos=input->tell();
1336
22.7k
    f.str("");
1337
22.7k
    f << "Layout-" << id << "[C2:" << i << "]:";
1338
22.7k
    ascii().addPos(pos);
1339
22.7k
    ascii().addNote(f.str().c_str());
1340
22.7k
    input->seek(pos+12, librevenge::RVNG_SEEK_SET);
1341
22.7k
  }
1342
1343
262
  pos=input->tell();
1344
262
  f.str("");
1345
262
  f << "Layout-" << id << "[C3]:";
1346
262
  ascii().addPos(pos);
1347
262
  ascii().addNote(f.str().c_str());
1348
1349
262
  input->seek(pos+1420, librevenge::RVNG_SEEK_SET);
1350
1351
  //--- end of unknown zone
1352
262
  pos=input->tell();
1353
262
  f.str("");
1354
262
  f << "Layout-" << id << "[D]:";
1355
262
  auto N=static_cast<int>(input->readULong(2));
1356
262
  f << "N=" << N << ",";
1357
262
  if (!input->checkPosition(pos+2+2*N)) {
1358
50
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can find zone D\n"));
1359
50
    f << "###";
1360
50
    ascii().addPos(pos);
1361
50
    ascii().addNote(f.str().c_str());
1362
50
    return false;
1363
50
  }
1364
212
  if (N) {
1365
34
    f << "lists=[";
1366
98.9k
    for (int i=0; i<N; ++i) f << input->readLong(2) << ",";
1367
34
    f << "],";
1368
34
  }
1369
212
  ascii().addPos(pos);
1370
212
  ascii().addNote(f.str().c_str());
1371
1372
212
  pos=input->tell();
1373
212
  f.str("");
1374
212
  f << "Layout-" << id << "[fields]:";
1375
212
  val=static_cast<int>(input->readULong(2));
1376
212
  auto type=static_cast<int>(input->readULong(2));
1377
212
  N=static_cast<int>(input->readULong(2));
1378
212
  f << "N=" << N << ",";
1379
212
  if (type!=0x5a || !input->checkPosition(pos+6+36*N)) {
1380
44
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can find field zone \n"));
1381
44
    f << "###";
1382
44
    ascii().addPos(pos);
1383
44
    ascii().addNote(f.str().c_str());
1384
44
    return false;
1385
44
  }
1386
168
  ascii().addPos(pos);
1387
168
  ascii().addNote(f.str().c_str());
1388
168
  BeagleWksDBParserInternal::Cell field;
1389
1.06k
  for (int i=0; i<N; i++) {
1390
896
    pos=input->tell();
1391
896
    f.str("");
1392
896
    f << "Layout-" << id << "[field" << i << "]:";
1393
896
    id=static_cast<int>(input->readLong(2));
1394
896
    if (id!=i) f << "id[field]=" << val << ",";
1395
896
    val=static_cast<int>(input->readLong(2));
1396
896
    if (val!=0x4b) f << "f0=" << val << ",";
1397
2.68k
    for (int j=0; j<2; ++j) { // j=0: field name, j=1: field content
1398
1.79k
      std::string extra("");
1399
1.79k
      if (!readFormat(field, extra)) {
1400
0
        f << "###";
1401
0
        break;
1402
0
      }
1403
1.79k
      f << "field" << j << "=[" << extra << "],";
1404
1.79k
    }
1405
2.68k
    for (int j=0; j<2; ++j) {
1406
1.79k
      int dim[4];
1407
7.16k
      for (auto &k : dim) k=static_cast<int>(input->readLong(2));
1408
1.79k
      f << "box" << j << "=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ",";
1409
1.79k
    }
1410
896
    ascii().addPos(pos);
1411
896
    ascii().addNote(f.str().c_str());
1412
896
    input->seek(pos+36, librevenge::RVNG_SEEK_SET);
1413
896
  }
1414
1415
168
  pos=input->tell();
1416
168
  f.str("");
1417
168
  f << "Layout-" << id << "[list]:";
1418
168
  dSz=static_cast<int>(input->readULong(2));
1419
168
  type=static_cast<int>(input->readLong(2));
1420
168
  N=static_cast<int>(input->readULong(2));
1421
168
  endPos=pos+6+dSz;
1422
168
  if (2*N>dSz || type!=0x75 || !input->checkPosition(endPos)) {
1423
26
    MWAW_DEBUG_MSG(("BeagleWksDBParser::readLayouts: can read zone F\n"));
1424
26
    f << "###";
1425
26
    ascii().addPos(pos);
1426
26
    ascii().addNote(f.str().c_str());
1427
26
    return false;
1428
26
  }
1429
142
  f << "N=" << N << ",";
1430
142
  if (val!=0x75) f << "f0=" << val << ",";
1431
142
  f << "lists=[";
1432
1.21k
  for (int i=0; i<N; ++i) f << input->readLong(2) << ",";
1433
142
  f << "],";
1434
142
  ascii().addPos(pos);
1435
142
  ascii().addNote(f.str().c_str());
1436
142
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1437
142
  return true;
1438
168
}
1439
1440
////////////////////////////////////////////////////////////
1441
// send data
1442
////////////////////////////////////////////////////////////
1443
bool BeagleWksDBParser::sendPageFrames()
1444
0
{
1445
0
  auto const &frameMap = m_structureManager->getIdFrameMap();
1446
0
  for (auto const &it : frameMap)
1447
0
    sendFrame(it.second);
1448
0
  return true;
1449
0
}
1450
1451
bool BeagleWksDBParser::sendFrame(BeagleWksStructManager::Frame const &frame)
1452
0
{
1453
0
  MWAWPosition fPos(MWAWVec2f(0,0), frame.m_dim, librevenge::RVNG_POINT);
1454
1455
0
  fPos.setPagePos(frame.m_page > 0 ? frame.m_page : 1, frame.m_origin);
1456
0
  fPos.setRelativePosition(MWAWPosition::Page);
1457
0
  fPos.m_wrapping = frame.m_wrap==0 ? MWAWPosition::WNone : MWAWPosition::WDynamic;
1458
1459
0
  auto style=MWAWGraphicStyle::emptyStyle();
1460
0
  style.setBorders(frame.m_bordersSet, frame.m_border);
1461
0
  return sendPicture(frame.m_pictId, fPos, true, style);
1462
0
}
1463
1464
// read/send picture (edtp resource)
1465
bool BeagleWksDBParser::sendPicture
1466
(int pId, MWAWPosition const &pictPos, bool readEDTP, MWAWGraphicStyle const &style)
1467
17
{
1468
17
  MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener();
1469
17
  if (!listener) {
1470
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::sendPicture: can not find the listener\n"));
1471
0
    return false;
1472
0
  }
1473
17
  auto rsrcParser = getRSRCParser();
1474
17
  if (!rsrcParser) {
1475
8
    static bool first=true;
1476
8
    if (first) {
1477
2
      MWAW_DEBUG_MSG(("BeagleWksDBParser::sendPicture: need access to resource fork to retrieve picture content\n"));
1478
2
      first=false;
1479
2
    }
1480
8
    return true;
1481
8
  }
1482
1483
9
  librevenge::RVNGBinaryData data;
1484
9
  if (!m_structureManager->readPicture(pId, data, readEDTP))
1485
9
    return false;
1486
1487
0
  listener->insertPicture(pictPos, MWAWEmbeddedObject(data, "image/pict"), style);
1488
0
  return true;
1489
9
}
1490
1491
bool BeagleWksDBParser::sendText(MWAWEntry const &entry, bool /*headerFooter*/)
1492
323
{
1493
323
  MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener();
1494
323
  if (!listener) {
1495
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::sendText: can not find the listener\n"));
1496
0
    return false;
1497
0
  }
1498
323
  if (!entry.valid()) {
1499
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::sendText: can not find the entry\n"));
1500
0
    return false;
1501
0
  }
1502
1503
323
  MWAWInputStreamPtr &input= getInput();
1504
323
  long endPos=entry.end();
1505
323
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1506
14.0k
  while (!input->isEnd()) {
1507
14.0k
    long pos=input->tell();
1508
14.0k
    if (pos>=endPos) break;
1509
13.7k
    auto c = static_cast<unsigned char>(input->readULong(1));
1510
13.7k
    switch (c) {
1511
172
    case 0x9:
1512
172
      listener->insertTab();
1513
172
      break;
1514
151
    case 0xd:
1515
151
      listener->insertEOL();
1516
151
      break;
1517
13.4k
    default:
1518
13.4k
      listener->insertCharacter(static_cast<unsigned char>(c));
1519
13.4k
      break;
1520
13.7k
    }
1521
13.7k
  }
1522
323
  return true;
1523
323
}
1524
1525
////////////////////////////////////////////////////////////
1526
////////////////////////////////////////////////////////////
1527
bool BeagleWksDBParser::sendDatabase()
1528
927
{
1529
927
  MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener();
1530
927
  if (!listener) {
1531
0
    MWAW_DEBUG_MSG(("BeagleWksDBParser::sendDatabase: I can not find the listener\n"));
1532
0
    return false;
1533
0
  }
1534
927
  MWAWInputStreamPtr input=getInput();
1535
927
  auto const &database=m_state->m_database;
1536
927
  auto const &fields = database.m_fields;
1537
927
  size_t numFields=fields.size();
1538
927
  auto const &records=database.m_records;
1539
927
  size_t numRecords=records.size();
1540
  // fixme: use first layout colWidth here
1541
927
  listener->openSheet(std::vector<float>(1,76), librevenge::RVNG_POINT, std::vector<int>(1,static_cast<int>(numRecords)), "Sheet0");
1542
10.2k
  for (size_t r=0; r<numRecords; ++r) {
1543
9.30k
    std::vector<MWAWCellContent> const &row=records[r];
1544
9.30k
    listener->openSheetRow(12, librevenge::RVNG_POINT);
1545
102k
    for (size_t c=0; c<row.size(); ++c) {
1546
93.2k
      if (c>=numFields) break;
1547
93.2k
      auto field=fields[c];
1548
93.2k
      database.updateWithContent(field, MWAWVec2i(int(c),int(r)), row[c]);
1549
93.2k
      if (field.empty()) continue;
1550
1551
16.3k
      auto const &content=field.m_content;
1552
16.3k
      listener->openSheetCell(field, content);
1553
16.3k
      if (content.m_contentType==MWAWCellContent::C_TEXT && content.m_textEntry.valid()) {
1554
3.51k
        listener->setFont(field.getFont());
1555
3.51k
        input->seek(content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET);
1556
60.8k
        while (!input->isEnd() && input->tell()<content.m_textEntry.end()) {
1557
59.9k
          auto ch=static_cast<unsigned char>(input->readULong(1));
1558
59.9k
          if (ch==0xd)
1559
848
            listener->insertEOL();
1560
59.1k
          else if (ch<30) {
1561
2.68k
            MWAW_DEBUG_MSG(("BeagleWksDBParser::sendDatabase: find some odd character\n"));
1562
2.68k
            break;
1563
2.68k
          }
1564
56.4k
          else
1565
56.4k
            listener->insertCharacter(ch);
1566
59.9k
        }
1567
3.51k
      }
1568
12.8k
      else if (field.m_type==BeagleWksDBParserInternal::Cell::Picture && field.m_pictureId>=0) {
1569
17
        std::string cellName("Sheet0.");
1570
17
        cellName+=MWAWCell::getBasicCellName(field.position()+MWAWVec2i(1,1));
1571
17
        MWAWPosition position(MWAWVec2f(0,0), MWAWVec2f(76,12), librevenge::RVNG_POINT); // changeme
1572
17
        position.setAnchorToCell(librevenge::RVNGString(cellName.c_str()));
1573
17
        sendPicture(field.m_pictureId, position, false);
1574
17
      }
1575
16.3k
      listener->closeSheetCell();
1576
16.3k
    }
1577
9.30k
    listener->closeSheetRow();
1578
9.30k
  }
1579
927
  listener->closeSheet();
1580
927
  return true;
1581
927
}
1582
1583
////////////////////////////////////////////////////////////
1584
//
1585
// Low level
1586
//
1587
////////////////////////////////////////////////////////////
1588
1589
////////////////////////////////////////////////////////////
1590
// read the header
1591
////////////////////////////////////////////////////////////
1592
bool BeagleWksDBParser::checkHeader(MWAWHeader *header, bool strict)
1593
14.2k
{
1594
14.2k
  *m_state = BeagleWksDBParserInternal::State();
1595
14.2k
  MWAWInputStreamPtr input = getInput();
1596
14.2k
  if (!input || !input->hasDataFork() || !input->checkPosition(66))
1597
190
    return false;
1598
1599
14.0k
  libmwaw::DebugStream f;
1600
14.0k
  f << "FileHeader:";
1601
1602
14.0k
  input->seek(0, librevenge::RVNG_SEEK_SET);
1603
14.0k
  if (input->readLong(2)!=0x4257 || input->readLong(2)!=0x6b73 ||
1604
13.9k
      input->readLong(2)!=0x4257 || input->readLong(2)!=0x6462 ||
1605
13.9k
      input->readLong(2)!=0x4257 || input->readLong(2)!=0x6462) {
1606
957
    return false;
1607
957
  }
1608
131k
  for (int i=0; i < 9; ++i) { // f2=f6=1 other 0
1609
117k
    auto val=static_cast<int>(input->readLong(2));
1610
117k
    if (val) f << "f" << i << "=" << val << ",";
1611
117k
  }
1612
13.1k
  setVersion(1);
1613
1614
13.1k
  if (header)
1615
9.71k
    header->reset(MWAWDocument::MWAW_T_BEAGLEWORKS, 1, MWAWDocument::MWAW_K_DATABASE);
1616
1617
13.1k
  ascii().addPos(0);
1618
13.1k
  ascii().addNote(f.str().c_str());
1619
1620
13.1k
  long pos=input->tell();
1621
13.1k
  f.str("");
1622
13.1k
  f << "FileHeader-II:";
1623
13.1k
  m_state->m_databaseBegin=input->readLong(4);
1624
13.1k
  if (!input->checkPosition(m_state->m_databaseBegin)) {
1625
2.34k
    MWAW_DEBUG_MSG(("BeagleWksDBParser::checkHeader: can not read the database position\n"));
1626
2.34k
    return false;
1627
2.34k
  }
1628
10.7k
  f << "database[ptr]=" << std::hex << m_state->m_databaseBegin << std::dec << ",";
1629
129k
  for (int i=0; i < 11; ++i) { // f2=0x50c|58c|5ac f3=f5=9
1630
118k
    long val=input->readLong(2);
1631
118k
    if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1632
118k
  }
1633
10.7k
  MWAWEntry entry;
1634
10.7k
  entry.setBegin(input->readLong(4));
1635
10.7k
  entry.setLength(input->readLong(4));
1636
10.7k
  entry.setId(static_cast<int>(input->readLong(2))); // in fact nFonts
1637
10.7k
  entry.setType("FontNames");
1638
10.7k
  f << "fontNames[ptr]=" << std::hex << entry.begin() << "<->" << entry.end()
1639
10.7k
    << std::dec << ",nFonts=" << entry.id() << ",";
1640
10.7k
  if (entry.length() && (!entry.valid() || !input->checkPosition(entry.end()))) {
1641
3.77k
    MWAW_DEBUG_MSG(("BeagleWksDBParser::checkHeader: can not read the font names position\n"));
1642
3.77k
    f << "###";
1643
3.77k
    ascii().addPos(pos);
1644
3.77k
    ascii().addNote(f.str().c_str());
1645
3.77k
    return false;
1646
3.77k
  }
1647
1648
6.98k
  m_state->m_typeEntryMap.insert
1649
6.98k
  (std::multimap<std::string, MWAWEntry>::value_type(entry.type(),entry));
1650
6.98k
  ascii().addPos(pos);
1651
6.98k
  ascii().addNote(f.str().c_str());
1652
6.98k
  if (strict && !readPrintInfo())
1653
270
    return false;
1654
6.71k
  ascii().addPos(66);
1655
6.71k
  ascii().addNote("_");
1656
1657
6.71k
  return true;
1658
6.98k
}
1659
1660
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: