1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  *  The Contents of this file are made available subject to the terms of
5  *  either of the following licenses
6  *
7  *         - GNU Lesser General Public License Version 2.1
8  *         - Sun Industry Standards Source License Version 1.1
9  *
10  *  Sun Microsystems Inc., October, 2000
11  *
12  *  GNU Lesser General Public License Version 2.1
13  *  =============================================
14  *  Copyright 2000 by Sun Microsystems, Inc.
15  *  901 San Antonio Road, Palo Alto, CA 94303, USA
16  *
17  *  This library is free software; you can redistribute it and/or
18  *  modify it under the terms of the GNU Lesser General Public
19  *  License version 2.1, as published by the Free Software Foundation.
20  *
21  *  This library is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  *  Lesser General Public License for more details.
25  *
26  *  You should have received a copy of the GNU Lesser General Public
27  *  License along with this library; if not, write to the Free Software
28  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29  *  MA  02111-1307  USA
30  *
31  *
32  *  Sun Industry Standards Source License Version 1.1
33  *  =================================================
34  *  The contents of this file are subject to the Sun Industry Standards
35  *  Source License Version 1.1 (the "License"); You may not use this file
36  *  except in compliance with the License. You may obtain a copy of the
37  *  License at http://www.openoffice.org/license.html.
38  *
39  *  Software provided under this License is provided on an "AS IS" basis,
40  *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
41  *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
42  *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
43  *  See the License for the specific provisions governing your rights and
44  *  obligations concerning the Software.
45  *
46  *  The Initial Developer of the Original Code is: IBM Corporation
47  *
48  *  Copyright: 2008 by IBM Corporation
49  *
50  *  All Rights Reserved.
51  *
52  *  Contributor(s): _______________________________________
53  *
54  *
55  ************************************************************************/
56 
57 #include <sal/config.h>
58 #include <sal/log.hxx>
59 
60 #include <cstring>
61 
62 #include "first.hxx"
63 #include "bentoid.hxx"
64 #include "tocread.hxx"
65 #include "ut.hxx"
66 #include <assert.h>
67 namespace OpenStormBento
68 {
69 
70 BenError
ReadLabelAndTOC()71 CBenTOCReader::ReadLabelAndTOC()
72 {
73     BenError Err;
74 
75     tools::ULong TOCOffset;
76     if ((Err = ReadLabel(&TOCOffset, &cTOCSize)) != BenErr_OK)
77         return Err;
78 
79     sal_uLong nLength = cpContainer->GetSize();
80 
81     if (TOCOffset > nLength)
82         return BenErr_ReadPastEndOfTOC;
83 
84     if (cTOCSize > nLength - TOCOffset)
85         return BenErr_ReadPastEndOfTOC;
86 
87     cpContainer->SeekToPosition(TOCOffset);
88 
89     cpTOC.reset( new BenByte[cTOCSize] );
90     if ((Err = cpContainer->ReadKnownSize(cpTOC.get(), cTOCSize)) != BenErr_OK)
91         return Err;
92 
93     if ((Err = ReadTOC()) != BenErr_OK)
94         return Err;
95 
96     return BenErr_OK;
97 }
98 
99 BenError
ReadLabel(tools::ULong * pTOCOffset,tools::ULong * pTOCSize)100 CBenTOCReader::ReadLabel(tools::ULong * pTOCOffset, tools::ULong * pTOCSize)
101 {
102     // If seek fails, then probably because stream is smaller than
103     // BEN_LABEL_SIZE and thus can't be Bento container
104     BenError Err;
105     cpContainer->SeekFromEnd(-BEN_LABEL_SIZE);
106 
107     BenByte Label[BEN_LABEL_SIZE];
108     if ((Err = cpContainer->ReadKnownSize(Label, BEN_LABEL_SIZE)) != BenErr_OK)
109         return Err;
110 
111     if (memcmp(Label, gsBenMagicBytes, BEN_MAGIC_BYTES_SIZE) != 0)
112         if ((Err = SearchForLabel(Label)) != BenErr_OK)
113             return Err;
114 
115     BenByte * pCurrLabel = Label + BEN_MAGIC_BYTES_SIZE;
116 
117     BenWord Flags =
118         UtGetIntelWord(pCurrLabel);
119     pCurrLabel += 2; // Flags
120     // Newer files are 0x0101--indicates if big or little endian.  Older
121     // files are 0x0 for flags
122     if (Flags != 0x0101 && Flags != 0x0)
123         return BenErr_UnknownBentoFormatVersion;
124 
125     cBlockSize = UtGetIntelWord(pCurrLabel) * 1024; pCurrLabel += 2;
126     if (cBlockSize == 0)
127         return BenErr_NotBentoContainer;
128 
129     // Check major version
130     if (UtGetIntelWord(pCurrLabel) != BEN_CURR_MAJOR_VERSION)
131         return BenErr_UnknownBentoFormatVersion;
132     pCurrLabel += 2;
133 
134     pCurrLabel += 2;    // Minor version
135 
136     *pTOCOffset = UtGetIntelDWord(pCurrLabel); pCurrLabel += 4;
137     *pTOCSize = UtGetIntelDWord(pCurrLabel);
138 
139     assert(pCurrLabel + 4 == Label + BEN_LABEL_SIZE);
140 
141     return BenErr_OK;
142 }
143 
144 #define LABEL_READ_BUFFER_SIZE 500
145 #define MAX_SEARCH_AMOUNT 1024 * 1024
146 
147 BenError
SearchForLabel(BenByte * pLabel)148 CBenTOCReader::SearchForLabel(BenByte * pLabel)
149 {
150     BenError Err;
151 
152     sal_uLong Length = cpContainer->GetSize();
153 
154     // Always ready to check for MagicBytes from
155     // CurrOffset - BEN_MAGIC_BYTES_SIZE to CurrOffset - 1
156     unsigned long CurrOffset = Length - BEN_LABEL_SIZE + BEN_MAGIC_BYTES_SIZE -
157       1;
158 
159     char Buffer[LABEL_READ_BUFFER_SIZE] = {0};
160 
161     unsigned long BufferStartOffset = Length;   // Init to big value
162 
163     while (CurrOffset >= BEN_MAGIC_BYTES_SIZE)
164     {
165         // Don't search backwards more than 1 meg
166         if (Length - CurrOffset > MAX_SEARCH_AMOUNT)
167             break;
168 
169         // If before beginning of buffer
170         if (CurrOffset - BEN_MAGIC_BYTES_SIZE < BufferStartOffset)
171         {
172             unsigned long UsedBufferSize;
173             if (CurrOffset < LABEL_READ_BUFFER_SIZE)
174                 UsedBufferSize = CurrOffset;
175             else UsedBufferSize = LABEL_READ_BUFFER_SIZE;
176 
177             cpContainer->SeekToPosition(CurrOffset - UsedBufferSize);
178 
179             if ((Err = cpContainer->ReadKnownSize(Buffer, UsedBufferSize)) !=
180               BenErr_OK)
181                 return Err;
182 
183             BufferStartOffset = CurrOffset - UsedBufferSize;
184         }
185 
186         if (memcmp(Buffer + (CurrOffset - BEN_MAGIC_BYTES_SIZE -
187           BufferStartOffset), gsBenMagicBytes, BEN_MAGIC_BYTES_SIZE) == 0)
188         {
189             cpContainer->SeekToPosition(CurrOffset -
190               BEN_MAGIC_BYTES_SIZE);
191 
192             return cpContainer->ReadKnownSize(pLabel, BEN_LABEL_SIZE);
193         }
194 
195         --CurrOffset;
196     }
197 
198     return BenErr_NotBentoContainer;    // Didn't find magic bytes
199 }
200 
201 BenError
ReadTOC()202 CBenTOCReader::ReadTOC()
203 {
204     BenError Err;
205     BenByte LookAhead = GetCode();
206     BenGeneration Generation = 0;
207 
208     // Read in all objects
209     while (LookAhead == BEN_NEW_OBJECT)
210     {
211         BenObjectID ObjectID;
212         if ((Err = GetDWord(&ObjectID)) != BenErr_OK)
213             return Err;
214         CBenObject * pObject = nullptr;
215 
216         // Read in all properties for object
217         do
218         {
219             BenObjectID PropertyID;
220 
221             if ((Err = GetDWord(&PropertyID)) != BenErr_OK)
222                 return Err;
223             CBenProperty * pProperty = nullptr;
224 
225             // Read in all values for property
226             do
227             {
228                 BenObjectID ReferencedListID = 0;
229 
230                 BenObjectID TypeID;
231                 if ((Err = GetDWord(&TypeID)) != BenErr_OK)
232                     return Err;
233                 LookAhead = GetCode();
234 
235                 if (LookAhead == BEN_EXPLICIT_GEN)
236                 {
237                     if ((Err = GetDWord(&Generation)) != BenErr_OK)
238                         return Err;
239                     LookAhead = GetCode();
240                 }
241 
242                 if (LookAhead == BEN_REFERENCE_LIST_ID)
243                 {
244                     if ((Err = GetDWord(&ReferencedListID)) != BenErr_OK)
245                         return Err;
246                     LookAhead = GetCode();
247                 }
248 
249                 if (PropertyID == BEN_PROPID_GLOBAL_PROPERTY_NAME ||
250                     PropertyID == BEN_PROPID_GLOBAL_TYPE_NAME)
251                 {
252                     // Read property or type name
253 
254                     if (pObject != nullptr || TypeID != BEN_TYPEID_7_BIT_ASCII ||
255                       LookAhead != BEN_OFFSET4_LEN4)
256                         return BenErr_NamedObjectError;
257 
258                     BenContainerPos Pos;
259                     sal_uInt32 Length;
260 
261                     if ((Err = GetDWord(&Pos)) != BenErr_OK)
262                         return Err;
263                     if ((Err = GetDWord(&Length)) != BenErr_OK)
264                         return Err;
265                     LookAhead = GetCode();
266 
267                     cpContainer->SeekToPosition(Pos);
268 
269                     const auto nRemainingSize = cpContainer->remainingSize();
270                     if (Length > nRemainingSize)
271                     {
272                         SAL_WARN("lwp", "stream too short for claimed no of records");
273                         Length = nRemainingSize;
274                     }
275 
276                     #define STACK_BUFFER_SIZE 256
277                     char sStackBuffer[STACK_BUFFER_SIZE];
278                     std::unique_ptr<char[]> sAllocBuffer;
279                     char * sBuffer;
280                     if (Length > STACK_BUFFER_SIZE)
281                     {
282                         sAllocBuffer.reset(new char[Length]);
283                         sBuffer = sAllocBuffer.get();
284                     }
285                     else
286                     {
287                         sBuffer = sStackBuffer;
288                     }
289 
290                     if ((Err = cpContainer->ReadKnownSize(sBuffer, Length)) !=
291                       BenErr_OK)
292                     {
293                         return Err;
294                     }
295 
296                     OString sName;
297                     if (Length)
298                         sName = OString(sBuffer, Length - 1);
299 
300                     CUtListElmt * pPrevNamedObjectListElmt;
301                     if (FindNamedObject(&cpContainer->GetNamedObjects(),
302                       sName, &pPrevNamedObjectListElmt) != nullptr)
303                     {
304                         return BenErr_DuplicateName;
305                     }
306 
307                     CUtListElmt* pPrevObject = cpContainer->GetObjects().GetLast();
308 
309                     if (PropertyID == BEN_PROPID_GLOBAL_PROPERTY_NAME)
310                         pObject = new CBenPropertyName(cpContainer, ObjectID,
311                            pPrevObject, sName, pPrevNamedObjectListElmt);
312                     else
313                         pObject = new CBenTypeName(cpContainer, ObjectID,
314                            pPrevObject, sName, pPrevNamedObjectListElmt);
315                 }
316                 else if (PropertyID == BEN_PROPID_OBJ_REFERENCES)
317                 {
318                     // Don't need to read in references object--we assume
319                     // that all references use object ID as key
320                     if ((Err = ReadSegments(nullptr, &LookAhead)) != BenErr_OK)
321                         return Err;
322                 }
323                 else if (ObjectID == BEN_OBJID_TOC)
324                 {
325                     if (PropertyID == BEN_PROPID_TOC_SEED)
326                     {
327                         if (TypeID != BEN_TYPEID_TOC_TYPE ||
328                           LookAhead !=  BEN_IMMEDIATE4)
329                             return BenErr_TOCSeedError;
330 
331                         BenDWord Data;
332                         if ((Err = GetDWord(&Data)) != BenErr_OK)
333                             return Err;
334                         LookAhead = GetCode();
335 
336                         cpContainer->SetNextAvailObjectID(Data);
337                     }
338                     else
339                     {
340                         // Ignore the other BEN_OBJID_TOC properties
341                         if ((Err = ReadSegments(nullptr, &LookAhead)) != BenErr_OK)
342                             return Err;
343                     }
344                 }
345                 else
346                 {
347                     if (pProperty != nullptr)
348                         return BenErr_PropertyWithMoreThanOneValue;
349 
350                     if (pObject == nullptr)
351                         pObject = new CBenObject(cpContainer, ObjectID,
352                           cpContainer->GetObjects().GetLast());
353 
354                     pProperty = new CBenProperty(pObject, PropertyID, TypeID,
355                       pObject->GetProperties().GetLast());
356 
357                     if ((Err = ReadSegments(&pProperty->UseValue(),
358                       &LookAhead)) != BenErr_OK)
359                         return Err;
360                 }
361             } while (LookAhead == BEN_NEW_TYPE);
362         } while (LookAhead == BEN_NEW_PROPERTY);
363     }
364 
365     if (LookAhead == BEN_READ_PAST_END_OF_TOC)
366         return BenErr_OK;
367     else return BenErr_InvalidTOC;
368 }
369 
370 BenError
ReadSegments(CBenValue * pValue,BenByte * pLookAhead)371 CBenTOCReader::ReadSegments(CBenValue * pValue, BenByte * pLookAhead)
372 {
373     BenError Err;
374 
375     while (*pLookAhead >= BEN_SEGMENT_CODE_START &&
376       *pLookAhead <= BEN_SEGMENT_CODE_END)
377     {
378         if ((Err = ReadSegment(pValue, pLookAhead)) !=
379           BenErr_OK)
380             return Err;
381     }
382 
383     return BenErr_OK;
384 }
385 
386 BenError
ReadSegment(CBenValue * pValue,BenByte * pLookAhead)387 CBenTOCReader::ReadSegment(CBenValue * pValue, BenByte * pLookAhead)
388 {
389     BenError Err;
390 
391     bool Immediate = false;
392     bool EightByteOffset = false;
393     sal_uInt32 Offset(0), Length(0);
394 
395     switch (*pLookAhead)
396     {
397         case BEN_CONT_OFFSET4_LEN4:
398         case BEN_OFFSET4_LEN4:
399             if ((Err = GetDWord(&Offset))  != BenErr_OK)
400                 return Err;
401             if ((Err = GetDWord(&Length))  != BenErr_OK)
402                 return Err;
403             break;
404 
405         case BEN_IMMEDIATE0:
406             Length = 0; Immediate = true;
407             break;
408 
409         case BEN_IMMEDIATE1:
410             Length = 1; Immediate = true;
411             break;
412 
413         case BEN_IMMEDIATE2:
414             Length = 2; Immediate = true;
415             break;
416 
417         case BEN_IMMEDIATE3:
418             Length = 3; Immediate = true;
419             break;
420 
421         case BEN_CONT_IMMEDIATE4:
422         case BEN_IMMEDIATE4:
423             Length = 4; Immediate = true;
424             break;
425 
426         case BEN_CONT_OFFSET8_LEN4:
427         case BEN_OFFSET8_LEN4:
428             EightByteOffset = true;
429             break;
430 
431         default:
432             return BenErr_OK;
433     }
434 
435     BenByte ImmData[4];
436     if (Immediate && Length != 0)
437         if ((Err = GetData(ImmData, 4)) != BenErr_OK)
438             return Err;
439 
440     *pLookAhead = GetCode();
441 
442     if (EightByteOffset)
443         return BenErr_64BitOffsetNotSupported;
444 
445     if (pValue != nullptr)
446     {
447         if (! Immediate)
448             new CBenValueSegment(pValue, Offset, Length);
449         else if (Length != 0)
450         {
451             assert(Length <= 4);
452             new CBenValueSegment(pValue, ImmData, static_cast<unsigned short>(Length));
453         }
454     }
455 
456     return BenErr_OK;
457 }
458 
459 bool
CanGetData(tools::ULong Amt)460 CBenTOCReader::CanGetData(tools::ULong Amt)
461 {
462     return cCurr + Amt <= cTOCSize;
463 }
464 
465 BenError
GetByte(BenByte * pByte)466 CBenTOCReader::GetByte(BenByte * pByte)
467 {
468     if (! CanGetData(1))
469         return BenErr_ReadPastEndOfTOC;
470 
471     *pByte = UtGetIntelByte(cpTOC.get() + cCurr);
472     ++cCurr;
473     return BenErr_OK;
474 }
475 
476 BenError
GetDWord(BenDWord * pDWord)477 CBenTOCReader::GetDWord(BenDWord * pDWord)
478 {
479     if (! CanGetData(4))
480         return BenErr_ReadPastEndOfTOC;
481 
482     *pDWord = UtGetIntelDWord(cpTOC.get() + cCurr);
483     cCurr += 4;
484     return BenErr_OK;
485 }
486 
487 BenByte
GetCode()488 CBenTOCReader::GetCode()
489 {
490     BenByte Code;
491     do
492     {
493         if (GetByte(&Code) != BenErr_OK)
494             return BEN_READ_PAST_END_OF_TOC;
495 
496         if (Code == BEN_END_OF_BUFFER)
497         {
498             assert(cBlockSize && "cBlockSize of 0 should have already caused BenErr_UnknownBentoFormatVersion in CBenTOCReader::ReadLabel");
499             // Advance to next block
500             cCurr = cBlockSize * ((cCurr + (cBlockSize - 1)) /
501               cBlockSize);
502         }
503     }
504     while (Code == BEN_NOOP || Code == BEN_END_OF_BUFFER);
505     return Code;
506 }
507 
508 BenError
GetData(void * pBuffer,tools::ULong Amt)509 CBenTOCReader::GetData(void * pBuffer, tools::ULong Amt)
510 {
511     if (! CanGetData(Amt))
512         return BenErr_ReadPastEndOfTOC;
513 
514     std::memcpy(pBuffer, cpTOC.get() + cCurr, Amt);
515     cCurr += Amt;
516     return BenErr_OK;
517 }
518 }//end OpenStormBento namespace
519 
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
521