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 #ifndef MWAW_INPUT_STREAM_H
35 #define MWAW_INPUT_STREAM_H
36 
37 #include <string>
38 #include <vector>
39 
40 #include <librevenge/librevenge.h>
41 #include <librevenge-stream/librevenge-stream.h>
42 #include "libmwaw_internal.hxx"
43 
44 /*! \class MWAWInputStream
45  * \brief Internal class used to read the file stream
46  *  Internal class used to read the file stream,
47  *    this class adds some usefull functions to the basic librevenge::RVNGInputStream:
48  *  - read number (int8, int16, int32) in low or end endian
49  *  - selection of a section of a stream
50  *  - read block of data
51  *  - interface with modified librevenge::RVNGOLEStream
52  */
53 class MWAWInputStream
54 {
55 public:
56   /*!\brief creates a stream with given endian
57    * \param input the given input
58    * \param inverted must be set to true for pc doc and ole part and to false for mac doc
59    */
60   MWAWInputStream(std::shared_ptr<librevenge::RVNGInputStream> input, bool inverted);
61 
62   /*!\brief creates a stream with given endian from an existing input
63    *
64    * Note: this functions does not delete input
65    */
66   MWAWInputStream(librevenge::RVNGInputStream *input, bool inverted, bool checkCompression=false);
67   //! destructor
68   ~MWAWInputStream();
69 
70   //! returns the basic librevenge::RVNGInputStream
input()71   std::shared_ptr<librevenge::RVNGInputStream> input()
72   {
73     return m_stream;
74   }
75   //! returns a new input stream corresponding to a librevenge::RVNGBinaryData
76   static std::shared_ptr<MWAWInputStream> get(librevenge::RVNGBinaryData const &data, bool inverted);
77 
78   //! returns the endian mode (see constructor)
readInverted() const79   bool readInverted() const
80   {
81     return m_inverseRead;
82   }
83   //! sets the endian mode
setReadInverted(bool newVal)84   void setReadInverted(bool newVal)
85   {
86     m_inverseRead = newVal;
87   }
88   //
89   // Position: access
90   //
91 
92   /*! \brief seeks to a offset position, from actual, beginning or ending position
93    * \return 0 if ok
94    * \sa pushLimit popLimit
95    */
96   int seek(long offset, librevenge::RVNG_SEEK_TYPE seekType);
97   //! returns actual offset position
98   long tell();
99   //! returns the stream size
size() const100   long size() const
101   {
102     return m_streamSize;
103   }
104   //! checks if a position is or not a valid file position
checkPosition(long pos) const105   bool checkPosition(long pos) const
106   {
107     if (pos < 0) return false;
108     if (m_readLimit > 0 && pos > m_readLimit) return false;
109     return pos<=m_streamSize;
110   }
111   //! returns true if we are at the end of the section/file
112   bool isEnd();
113 
114   /*! \brief defines a new section in the file (from actualPos to newLimit)
115    * next call of seek, tell, atEos, ... will be restrained to this section
116    */
pushLimit(long newLimit)117   void pushLimit(long newLimit)
118   {
119     m_prevLimits.push_back(m_readLimit);
120     m_readLimit = newLimit > m_streamSize ? m_streamSize : newLimit;
121   }
122   //! pops a section defined by pushLimit
popLimit()123   void popLimit()
124   {
125     if (!m_prevLimits.empty()) {
126       m_readLimit = m_prevLimits.back();
127       m_prevLimits.pop_back();
128     }
129     else m_readLimit = -1;
130   }
131 
132   /*! internal: recomputes the stream size, must be called after you modify the data of the main input
133 
134     For instance, if this input stream is created from a MWAWStringStream and you decide to add some data
135     in the original MWAWStringStream...
136    */
137   void recomputeStreamSize();
138 
139   //
140   // get data
141   //
142 
143   //! returns a uint8, uint16, uint32 readed from actualPos
readULong(int num)144   unsigned long readULong(int num)
145   {
146     return readULong(m_stream.get(), num, 0, m_inverseRead);
147   }
148   //! return a int8, int16, int32 readed from actualPos
149   long readLong(int num);
150   //! try to read a double of size 8: 1.5 bytes exponent, 6.5 bytes mantisse
151   bool readDouble8(double &res, bool &isNotANumber);
152   //! try to read a double of size 8: 6.5 bytes mantisse, 1.5 bytes exponent
153   bool readDoubleReverted8(double &res, bool &isNotANumber);
154   //! try to read a double of size 10: 2 bytes exponent, 8 bytes mantisse
155   bool readDouble10(double &res, bool &isNotANumber);
156 
157   /**! reads numbytes data, WITHOUT using any endian or section consideration
158    * \return a pointer to the read elements
159    */
160   const uint8_t *read(size_t numBytes, unsigned long &numBytesRead);
161   /*! \brief internal function used to read num byte,
162    *  - where a is the previous read data
163    */
164   static unsigned long readULong(librevenge::RVNGInputStream *stream, int num, unsigned long a, bool inverseRead);
165 
166   //! reads a librevenge::RVNGBinaryData with a given size in the actual section/file
167   bool readDataBlock(long size, librevenge::RVNGBinaryData &data);
168   //! reads a librevenge::RVNGBinaryData from actPos to the end of the section/file
169   bool readEndDataBlock(librevenge::RVNGBinaryData &data);
170 
171   //
172   // OLE/Zip access
173   //
174 
175   //! return true if the stream is ole
176   bool isStructured();
177   //! returns the number of substream
178   unsigned subStreamCount();
179   //! returns the name of the i^th substream
180   std::string subStreamName(unsigned id);
181 
182   //! return a new stream for a ole zone
183   std::shared_ptr<MWAWInputStream> getSubStreamByName(std::string const &name);
184   //! return a new stream for a ole zone
185   std::shared_ptr<MWAWInputStream> getSubStreamById(unsigned id);
186 
187   //
188   // Finder Info access
189   //
190   /** returns the finder info type and creator (if known) */
getFinderInfo(std::string & type,std::string & creator) const191   bool getFinderInfo(std::string &type, std::string &creator) const
192   {
193     if (!m_fInfoType.length() || !m_fInfoCreator.length()) {
194       type = creator = "";
195       return false;
196     }
197     type = m_fInfoType;
198     creator = m_fInfoCreator;
199     return true;
200   }
201 
202   //
203   // Resource Fork access
204   //
205 
206   /** returns true if the data fork block exists */
hasDataFork() const207   bool hasDataFork() const
208   {
209     return bool(m_stream);
210   }
211   /** returns true if the resource fork block exists */
hasResourceFork() const212   bool hasResourceFork() const
213   {
214     return bool(m_resourceFork);
215   }
216   /** returns the resource fork if find */
getResourceForkStream()217   std::shared_ptr<MWAWInputStream> getResourceForkStream()
218   {
219     return m_resourceFork;
220   }
221 
222 
223 protected:
224   //! update the stream size ( must be called in the constructor )
225   void updateStreamSize();
226   //! internal function used to read a byte
227   static uint8_t readU8(librevenge::RVNGInputStream *stream);
228 
229   //! unbinhex the data in the file is a BinHex 4.0 file of a mac file
230   bool unBinHex();
231   //! unzip the data in the file is a zip file of a mac file
232   bool unzipStream();
233   //! check if some stream are in MacMIME format, if so de MacMIME
234   bool unMacMIME();
235   //! de MacMIME an input stream
236   bool unMacMIME(MWAWInputStream *input,
237                  std::shared_ptr<librevenge::RVNGInputStream> &dataInput,
238                  std::shared_ptr<librevenge::RVNGInputStream> &rsrcInput) const;
239   //! check if a stream is an internal merge stream
240   bool unsplitInternalMergeStream();
241 
242 private:
243   MWAWInputStream(MWAWInputStream const &orig) = delete;
244   MWAWInputStream &operator=(MWAWInputStream const &orig) = delete;
245 
246 protected:
247   //! the initial input
248   std::shared_ptr<librevenge::RVNGInputStream> m_stream;
249   //! the stream size
250   long m_streamSize;
251 
252   //! actual section limit (-1 if no limit)
253   long m_readLimit;
254   //! list of previous limits
255   std::vector<long> m_prevLimits;
256 
257   //! finder info type
258   mutable std::string m_fInfoType;
259   //! finder info type
260   mutable std::string m_fInfoCreator;
261   //! the resource fork
262   std::shared_ptr<MWAWInputStream> m_resourceFork;
263   //! big or normal endian
264   bool m_inverseRead;
265 };
266 
267 #endif
268 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
269