~zorba-coders/zorba/1188033

23.1.2 by Juan Zacarias
Added FLWOR Foundation Copyright notice to files that missed it.
1
/*
2
 * Copyright 2012 The FLWOR Foundation.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * 
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
48 by Paul J. Lucas
Include file clean-up.
17
#include <algorithm>
18
#include <cassert>
19
#include <cstdio>
20
#include <fstream>
21
#include <iostream>
22
#include <string>
23
#include <sys/types.h>
24
25
#include <sys/timeb.h>
26
#ifdef UNIX
27
# include <sys/time.h>
28
#endif
29
#ifdef WIN32
30
# include <strptime.h>
31
# include <MMSystem.h>
32
#endif
33
34
#include <zorba/diagnostic_list.h>
35
#include <zorba/empty_sequence.h>
5 by Juan Zacarias
Changed name to archive module
36
#include <zorba/item_factory.h>
37
#include <zorba/singleton_item_sequence.h>
38
#include <zorba/user_exception.h>
49 by Paul J. Lucas
Include file clean-up.
39
#include <zorba/util/base64_util.h>
48 by Paul J. Lucas
Include file clean-up.
40
#include <zorba/util/base64_stream.h>
41
#include <zorba/util/transcode_stream.h>
5 by Juan Zacarias
Changed name to archive module
42
43
#include "archive.h"
44
#include "archive_entry.h"
48 by Paul J. Lucas
Include file clean-up.
45
#include "archive_module.h"
35 by Matthias Brantner
- reworked the way options are passed and named
46
#include "config.h"
5 by Juan Zacarias
Changed name to archive module
47
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
48
#define ERROR_ENTRY_COUNT_MISMATCH "ENTRY-COUNT"
49
#define ERROR_INVALID_OPTIONS "INVALID-OPTIONS"
50
#define ERROR_INVALID_ENTRY_VALS "INVALID-ENTRY-VALS"
51
#define ERROR_INVALID_ENCODING "INVALID-ENCODING"
52
#define ERROR_CORRUPTED_ARCHIVE "CORRUPTED-ARCHIVE"
53
#define ERROR_DIFFERENT_COMPRESSIONS_NOT_SUPPORTED "DIFFERENT-COMPRESSIONS-NOT-SUPPORTED"
54
53 by Luis Rodriguez Gonzalez
All comments fixed
55
#define FORMAT_KEY_NAME "format"
56
#define COMPRESSION_KEY_NAME "compression"
57
#define NAME_KEY_NAME "name"
58
#define TYPE_KEY_NAME "type"
59
#define SIZE_KEY_NAME "size"
60
#define LAST_MODIFIED_KEY_NAME "last-modified"
61
#define ENCODING_KEY_NAME "encoding"
62
7 by Matthias Brantner
fixed two build problems:
63
namespace zorba { namespace archive {
64
65
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
66
/*******************************************************************************
67
 ******************************************************************************/
7 by Matthias Brantner
fixed two build problems:
68
  zorba::ExternalFunction*
69
    ArchiveModule::getExternalFunction(const zorba::String& localName)
70
  {
71
    FuncMap_t::iterator lIte = theFunctions.find(localName);
72
73
    ExternalFunction*& lFunc = theFunctions[localName];
74
75
    if (lIte == theFunctions.end())
76
    {
77
      if (localName == "create")
78
      {
79
        lFunc = new CreateFunction(this);
80
      }
81
      else if (localName == "entries")
82
      {
83
        lFunc = new EntriesFunction(this);
84
      }
85
      else if (localName == "extract-text")
86
      {
87
        lFunc = new ExtractTextFunction(this);
88
      }
89
      else if (localName == "extract-binary")
90
      {
91
        lFunc = new ExtractBinaryFunction(this);
92
      }
93
      else if (localName == "delete")
94
      {
95
        lFunc = new DeleteFunction(this);
96
      }
97
      else if (localName == "update")
98
      {
99
        lFunc = new UpdateFunction(this);
100
      }
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
101
      else if (localName == "options")
102
      {
103
        lFunc = new OptionsFunction(this);
104
      }
7 by Matthias Brantner
fixed two build problems:
105
    }
106
107
    return lFunc;
108
  }
109
110
  void ArchiveModule::destroy()
111
  {
112
    delete this;
113
  }
114
115
  ArchiveModule::~ArchiveModule()
116
  {
117
    for (FuncMap_t::const_iterator lIter = theFunctions.begin();
118
      lIter != theFunctions.end(); ++lIter)
119
    {
120
      delete lIter->second;
121
    }
122
    theFunctions.clear();
123
  }
124
9 by Matthias Brantner
- introduced a schema for entries and options
125
  zorba::Item
126
  ArchiveModule::createDateTimeItem(time_t& aTime)
127
  {
42.1.4 by Matthias Brantner
use UTC instead of no timezone
128
    // create a datetime item with UTC as timezone
129
    // this seems to be what mtime from libarchive returns
9 by Matthias Brantner
- introduced a schema for entries and options
130
    struct ::tm gmtm;
131
#ifdef WIN32
42.1.4 by Matthias Brantner
use UTC instead of no timezone
132
    gmtime_s(&gmtm, &aTime);
9 by Matthias Brantner
- introduced a schema for entries and options
133
#else
42.1.4 by Matthias Brantner
use UTC instead of no timezone
134
    gmtime_r(&aTime, &gmtm);
9 by Matthias Brantner
- introduced a schema for entries and options
135
#endif
136
42.1.6 by luisrod
- Added ability to create directories
137
    // create a datetime item without timezone because
138
    // this is what the entry tells us (at least for zip)
9 by Matthias Brantner
- introduced a schema for entries and options
139
    Item lModifiedItem = getItemFactory()->createDateTime(
140
        static_cast<short>(gmtm.tm_year + 1900),
141
        static_cast<short>(gmtm.tm_mon + 1),
142
        static_cast<short>(gmtm.tm_mday),
143
        static_cast<short>(gmtm.tm_hour),
144
        static_cast<short>(gmtm.tm_min),
42.1.4 by Matthias Brantner
use UTC instead of no timezone
145
        gmtm.tm_sec,
146
        0);
9 by Matthias Brantner
- introduced a schema for entries and options
147
    return lModifiedItem;
148
  }
149
20 by Matthias Brantner
properly set value for last-modified attribute (use current time if no value is given for an entry)
150
  void
151
  ArchiveModule::parseDateTimeItem(const zorba::Item& i, time_t& t)
152
  {
153
    const char* lTime = i.getStringValue().c_str();
154
155
    struct tm tm;
156
    memset(&tm, 0, sizeof(struct tm));
157
158
    char* lTmp = strptime(lTime, "%Y-%m-%dT%T", &tm);
159
    if (lTmp != lTime + 19)
160
    {
161
      std::ostringstream lMsg;
162
      lMsg << i.getStringValue()
163
        << ": invalid value for last-modified attribute ";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
164
      ArchiveFunction::throwError(ERROR_INVALID_ENTRY_VALS, lMsg.str().c_str());
20 by Matthias Brantner
properly set value for last-modified attribute (use current time if no value is given for an entry)
165
    }
166
  }
167
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
168
/*******************************************************************************
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
169
 ****************************** ArchiveFunction ********************************
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
170
 ******************************************************************************/
7 by Matthias Brantner
fixed two build problems:
171
  ArchiveFunction::ArchiveFunction(const ArchiveModule* aModule)
172
    : theModule(aModule)
173
  {
174
  }
175
176
  ArchiveFunction::~ArchiveFunction()
177
  {
178
  }
179
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
180
181
  /******************
182
  ** Archive Entry **
183
  ******************/
184
17 by Matthias Brantner
first very basic version of create#2 and #3
185
  ArchiveFunction::ArchiveEntry::ArchiveEntry()
42.1.6 by luisrod
- Added ability to create directories
186
    : theEncoding("UTF-8"),
187
      theEntryType(regular)
17 by Matthias Brantner
first very basic version of create#2 and #3
188
  {
20 by Matthias Brantner
properly set value for last-modified attribute (use current time if no value is given for an entry)
189
    // use current time as a default for each entry
190
#if defined (WIN32)
191
    struct _timeb timebuffer;
192
    _ftime_s( &timebuffer );
193
#else
194
    struct timeb timebuffer;
195
    ftime( &timebuffer );
196
#endif
197
    theLastModified = timebuffer.time;
17 by Matthias Brantner
first very basic version of create#2 and #3
198
  }
199
200
  void
28 by Juan Zacarias
Implemented the add in the archive update function
201
  ArchiveFunction::ArchiveEntry::setValues(struct archive_entry* aEntry)
202
  {
203
    theEntryPath = archive_entry_pathname(aEntry);
204
205
    if (archive_entry_size_is_set(aEntry))
206
    {
42.1.6 by luisrod
- Added ability to create directories
207
      theSize = (int)archive_entry_size(aEntry);
28 by Juan Zacarias
Implemented the add in the archive update function
208
    }
209
210
    if (archive_entry_mtime_is_set(aEntry))
211
    {
212
      theLastModified = archive_entry_mtime(aEntry);
213
    }
214
    //check if it is encoded
42.1.6 by luisrod
- Added ability to create directories
215
216
    switch(archive_entry_filetype(aEntry))
217
    {
218
      case AE_IFDIR: theEntryType = directory; break;
219
      default: theEntryType = regular; break;
220
    }
28 by Juan Zacarias
Implemented the add in the archive update function
221
  }
222
223
  void
17 by Matthias Brantner
first very basic version of create#2 and #3
224
  ArchiveFunction::ArchiveEntry::setValues(zorba::Item& aEntry)
225
  {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
226
    if (aEntry.isJSONItem())
17 by Matthias Brantner
first very basic version of create#2 and #3
227
    {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
228
      Item lKey;
17 by Matthias Brantner
first very basic version of create#2 and #3
229
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
230
      Iterator_t lKeyIter = aEntry.getObjectKeys();
231
      lKeyIter->open();
232
      while (lKeyIter->next(lKey))
17 by Matthias Brantner
first very basic version of create#2 and #3
233
      {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
234
        Item lKeyValue;
235
        lKeyValue = aEntry.getObjectValue(lKey.getStringValue());
17 by Matthias Brantner
first very basic version of create#2 and #3
236
53 by Luis Rodriguez Gonzalez
All comments fixed
237
        if(lKey.getStringValue() == NAME_KEY_NAME)
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
238
        {
239
          theEntryPath = lKeyValue.getStringValue();
240
        }
53 by Luis Rodriguez Gonzalez
All comments fixed
241
        else if(lKey.getStringValue() == TYPE_KEY_NAME)
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
242
        {
243
          String filetype = lKeyValue.getStringValue();
42.1.6 by luisrod
- Added ability to create directories
244
          if(filetype == "directory")
245
          {
246
            theEntryType = directory;
247
          }
248
        }
53 by Luis Rodriguez Gonzalez
All comments fixed
249
        else if (lKey.getStringValue() == LAST_MODIFIED_KEY_NAME)
17 by Matthias Brantner
first very basic version of create#2 and #3
250
        {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
251
          ArchiveModule::parseDateTimeItem(lKeyValue, theLastModified);
17 by Matthias Brantner
first very basic version of create#2 and #3
252
        }
53 by Luis Rodriguez Gonzalez
All comments fixed
253
        else if (lKey.getStringValue() == ENCODING_KEY_NAME)
17 by Matthias Brantner
first very basic version of create#2 and #3
254
        {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
255
          theEncoding = lKeyValue.getStringValue();
21 by Matthias Brantner
- case insensitive entry and format options
256
          std::transform(
257
              theEncoding.begin(), theEncoding.end(),
258
              theEncoding.begin(), ::toupper);
259
          if (!transcode::is_supported(theEncoding.c_str()))
260
          {
261
            std::ostringstream lMsg;
262
            lMsg << theEncoding << ": unsupported encoding";
263
              
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
264
            throwError(ERROR_INVALID_ENCODING, lMsg.str().c_str());
21 by Matthias Brantner
- case insensitive entry and format options
265
          }
17 by Matthias Brantner
first very basic version of create#2 and #3
266
        }
53 by Luis Rodriguez Gonzalez
All comments fixed
267
        else if (lKey.getStringValue() == COMPRESSION_KEY_NAME)
42 by Matthias Brantner
- new option skip-extra-attrs (same effect as zip -X) but needs a special version of libarchive
268
        {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
269
          theCompression = lKeyValue.getStringValue();
35 by Matthias Brantner
- reworked the way options are passed and named
270
          std::transform(
271
              theCompression.begin(),
272
              theCompression.end(),
273
              theCompression.begin(), ::toupper);
31 by luisrod
- Code added to provide options for each entry
274
        }
17 by Matthias Brantner
first very basic version of create#2 and #3
275
      }
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
276
    } else
277
        theEntryPath = aEntry.getStringValue();
17 by Matthias Brantner
first very basic version of create#2 and #3
278
  }
279
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
280
  /********************
281
  ** Archive Options **
282
  ********************/
283
17 by Matthias Brantner
first very basic version of create#2 and #3
284
  ArchiveFunction::ArchiveOptions::ArchiveOptions()
35 by Matthias Brantner
- reworked the way options are passed and named
285
    : theCompression("DEFLATE"),
42 by Matthias Brantner
- new option skip-extra-attrs (same effect as zip -X) but needs a special version of libarchive
286
      theFormat("ZIP"),
287
      theSkipExtraAttrs(false)
17 by Matthias Brantner
first very basic version of create#2 and #3
288
  {}
289
290
  void
28 by Juan Zacarias
Implemented the add in the archive update function
291
  ArchiveFunction::ArchiveOptions::setValues(struct archive* aArchive)
292
  {
35 by Matthias Brantner
- reworked the way options are passed and named
293
    theCompression = ArchiveFunction::compressionName(
294
        archive_compression(aArchive));
28 by Juan Zacarias
Implemented the add in the archive update function
295
    theFormat = ArchiveFunction::formatName(archive_format(aArchive));
296
  }
297
298
  void
17 by Matthias Brantner
first very basic version of create#2 and #3
299
  ArchiveFunction::ArchiveOptions::setValues(Item& aOptions)
300
  {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
301
    if(aOptions.isJSONItem())
302
    {
303
      Item lOptionKey;
304
      Iterator_t lKeyIter = aOptions.getObjectKeys();
305
      lKeyIter->open();
306
307
      while (lKeyIter->next(lOptionKey))
308
      {
309
        Item lOptionValue;
310
        lOptionValue = aOptions.getObjectValue(lOptionKey.getStringValue());
311
53 by Luis Rodriguez Gonzalez
All comments fixed
312
        if (lOptionKey.getStringValue() == COMPRESSION_KEY_NAME)
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
313
        {
314
          theCompression = lOptionValue.getStringValue().c_str();
315
          std::transform(
316
              theCompression.begin(),
317
              theCompression.end(),
318
              theCompression.begin(), ::toupper);
319
        }
53 by Luis Rodriguez Gonzalez
All comments fixed
320
        else if (lOptionKey.getStringValue() == FORMAT_KEY_NAME)
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
321
        {
322
          theFormat = lOptionValue.getStringValue().c_str();
323
          std::transform(
324
              theFormat.begin(),
325
              theFormat.end(),
326
              theFormat.begin(), ::toupper);
327
        }
328
        else if (lOptionKey.getStringValue() == "skip-extra-attributes")
329
        {
330
          theSkipExtraAttrs = lOptionValue.getStringValue() == "true" ? true : false;
331
        }
332
      }
333
      if (theFormat == "ZIP")
334
      {
335
        if (theCompression != "STORE" && theCompression != "DEFLATE" && theCompression != "NONE")
336
        {
337
          std::ostringstream lMsg;
338
          lMsg
339
            << theCompression
340
            << ": compression algorithm not supported for ZIP format (required: deflate, store)";
341
          throwError(ERROR_INVALID_OPTIONS, lMsg.str().c_str());
342
        }
343
      }
344
      if (theFormat == "TAR")
53 by Luis Rodriguez Gonzalez
All comments fixed
345
      {        if (theCompression != "GZIP"
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
346
#ifndef WIN32
347
            && theCompression != "BZIP2"
348
            && theCompression != "LZMA"
349
#endif
350
          )
351
        {
352
          std::ostringstream lMsg;
353
          lMsg
354
            << theCompression
355
            << ": compression algorithm not supported for TAR format (required: gzip"
356
#ifndef WIN32
357
            << ", bzip2, lzma"
358
#endif
359
            << ")";
360
          throwError(ERROR_INVALID_OPTIONS, lMsg.str().c_str());
361
        }
36 by Matthias Brantner
better errors + removed support for exotic formats and compressions
362
      }
363
    }
15 by Juan Zacarias
Partial implementation of create function
364
  }
365
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
366
  /************************
367
  ** Archive Compressor ***
368
  ************************/
369
370
  ArchiveFunction::ArchiveCompressor::ArchiveCompressor()
371
    : theArchive(0),
372
      theEntry(0),
373
      theStream(new std::stringstream())
374
  {
375
    theEntry = archive_entry_new();
376
  }
377
378
  ArchiveFunction::ArchiveCompressor::~ArchiveCompressor()
379
  {
380
    archive_entry_free(theEntry);
381
  }
382
383
  void
384
  ArchiveFunction::ArchiveCompressor::setOptions(const ArchiveOptions& aOptions)
385
  {
35 by Matthias Brantner
- reworked the way options are passed and named
386
    theOptions = aOptions;
387
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
388
    int lFormatCode = formatCode(aOptions.getFormat().c_str());
389
    int lErr = archive_write_set_format(theArchive, lFormatCode);
390
    ArchiveFunction::checkForError(lErr, 0, theArchive);
391
35 by Matthias Brantner
- reworked the way options are passed and named
392
    int lCompressionCode = compressionCode(aOptions.getCompression().c_str());
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
393
    setArchiveCompression(theArchive, lCompressionCode);
394
42 by Matthias Brantner
- new option skip-extra-attrs (same effect as zip -X) but needs a special version of libarchive
395
    if (aOptions.getSkipExtraAttrs())
396
    {
397
      // ignore result value because some libarchive versions
398
      // don't support this option
399
      archive_write_set_options(theArchive, "zip:skip-extras=true");
400
    }
401
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
402
    lErr = archive_write_open(
403
        theArchive, this, 0, ArchiveFunction::writeStream, 0);
404
    ArchiveFunction::checkForError(lErr, 0, theArchive);
405
  }
406
407
  bool
408
  ArchiveFunction::ArchiveCompressor::getStreamForString(
409
      const zorba::String& aEncoding,
410
      zorba::Item& aFile,
411
      std::istream*& aResStream,
412
      uint64_t& aResFileSize) const
413
  {
414
    // 1. always need to materialize if transcoding is necessary
415
    //    or stream is not seekable to compute resulting file size
416
    if (aFile.isStreamable() &&
417
        (!aFile.isSeekable() ||
418
         transcode::is_necessary(aEncoding.c_str())))
419
    {
420
      aResStream = &aFile.getStream();
421
422
      if (transcode::is_necessary(aEncoding.c_str()))
423
      {
424
        transcode::attach(*aResStream, aEncoding.c_str());
425
      }
426
427
      std::stringstream* lStream = new std::stringstream();
428
429
      char lBuf[ZORBA_ARCHIVE_MAX_READ_BUF];
430
      while (aResStream->good())
431
      {
432
        aResStream->read(lBuf, ZORBA_ARCHIVE_MAX_READ_BUF);
433
        lStream->write(lBuf, aResStream->gcount());
434
        aResFileSize += aResStream->gcount();
435
      }
436
      aResStream = lStream;
437
      return true; // delete after use
438
    }
439
    // 2. seekable and no transcoding is best cast
440
    //    => compute size by seeking and return stream as-is
441
    else if (aFile.isStreamable())
442
    {
443
      aResStream = &aFile.getStream();
444
445
      aResStream->seekg(0, std::ios::end);
446
      aResFileSize = aResStream->tellg();
447
      aResStream->seekg(0, std::ios::beg);
448
      return false;
449
    }
450
    // 3. non-streamable string
451
    else
452
    {
453
      std::stringstream* lStream = new std::stringstream();
454
455
      //    3.1 with transcoding
456
      if (transcode::is_necessary(aEncoding.c_str()))
457
      {
458
        transcode::stream<std::istringstream> lTranscoder(
459
            aEncoding.c_str(),
460
            aFile.getStringValue().c_str()
461
          );
462
        char lBuf[ZORBA_ARCHIVE_MAX_READ_BUF];
463
        while (lTranscoder.good())
464
        {
465
          lTranscoder.read(lBuf, ZORBA_ARCHIVE_MAX_READ_BUF);
466
          lStream->write(lBuf, lTranscoder.gcount());
467
          aResFileSize += lTranscoder.gcount();
468
        }
469
      }
470
      else // 3.2 without transcoding
471
      {
472
        zorba::String lString = aFile.getStringValue();
473
        aResFileSize = lString.length();
474
        lStream->write(lString.c_str(), aResFileSize);
475
      }
476
      aResStream = lStream;
477
      return true;
478
    }
479
  }
480
481
  bool
482
  ArchiveFunction::ArchiveCompressor::getStreamForBase64(
483
      zorba::Item& aFile,
484
      std::istream*& aResStream,
485
      uint64_t& aResFileSize) const
486
  {
487
    if (aFile.isStreamable() && aFile.isSeekable())
488
    {
489
      aResStream = &aFile.getStream();
490
491
      aResStream->seekg(0, std::ios::end);
492
      aResFileSize = aResStream->tellg();
493
      aResStream->seekg(0, std::ios::beg);
494
495
      if (aFile.isEncoded())
496
      {
497
        base64::attach(*aResStream);
498
        // compute the size of the stream after base64 decoding
499
        aResFileSize = ((aResFileSize / 4) + !!(aResFileSize % 4)) * 3;
500
      }
501
      return false;
502
    }
503
    else
504
    {
505
      std::stringstream* lStream = new std::stringstream();
506
507
      size_t lResFileSize;
508
      const char* lBinValue = aFile.getBase64BinaryValue(lResFileSize);
509
510
      if (aFile.isEncoded())
511
      {
512
        zorba::String lEncoded(lBinValue, lResFileSize);
48 by Paul J. Lucas
Include file clean-up.
513
        zorba::String lDecoded = zorba::base64::decode(lEncoded);
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
514
        lStream->write(lDecoded.c_str(), lDecoded.length());
515
        aResFileSize = lDecoded.size();
516
      }
517
      else
518
      {
519
        lStream->write(lBinValue, lResFileSize);
520
        aResFileSize = lResFileSize;
521
      }
522
      aResStream = lStream;
523
      return true;
524
    }
525
  }
526
527
  bool
528
  ArchiveFunction::ArchiveCompressor::getStream(
529
      const ArchiveEntry& aEntry,
530
      zorba::Item& aFile,
531
      std::istream*& aResStream,
532
      uint64_t& aResFileSize) const
533
  {
534
    aResFileSize = 0;
535
536
    switch (aFile.getTypeCode())
537
    {
538
      case store::XS_STRING:
539
      {
540
        const zorba::String& lEncoding = aEntry.getEncoding();
541
542
        return getStreamForString(lEncoding, aFile, aResStream, aResFileSize);
543
      }
544
      case store::XS_BASE64BINARY:
545
      {
546
        return getStreamForBase64(aFile, aResStream, aResFileSize);
547
      }
548
      default:
549
      {
550
        String errNS("http://www.w3.org/2005/xqt-errors");
551
        Item errQName = ArchiveModule::getItemFactory()->createQName(
552
            errNS, "FORG0006");
553
        std::ostringstream lMsg;
554
        lMsg << aFile.getType().getStringValue()
555
          << ": invalid content argument "
556
          << "(xs:string or xs:base64binary)";
557
        throw USER_EXCEPTION(errQName, lMsg.str());
558
      }
559
    }
560
561
  }
562
563
  void
564
  ArchiveFunction::ArchiveCompressor::open(
565
    const ArchiveOptions& aOptions)
566
  {
567
    theArchive = archive_write_new();
568
569
    if (!theArchive)
570
      ArchiveFunction::throwError(
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
571
        ERROR_CORRUPTED_ARCHIVE, "internal error (couldn't create archive)");
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
572
573
    setOptions(aOptions);
574
  }
575
576
  void
577
  ArchiveFunction::ArchiveCompressor::compress(
578
    const std::vector<ArchiveEntry>& aEntries,
579
    zorba::Iterator_t& aFiles)
580
  {  
581
    zorba::Item lFile;
582
    aFiles->open();
583
584
    for (size_t i = 0; i < aEntries.size(); ++i)
585
    {
42.1.6 by luisrod
- Added ability to create directories
586
      if(aEntries[i].getEntryType() == ArchiveEntry::regular)
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
587
      {
42.1.6 by luisrod
- Added ability to create directories
588
        if (!aFiles->next(lFile))
589
        {
590
          std::ostringstream lMsg;
591
          lMsg << "number of entries (" << aEntries.size()
592
            << ") doesn't match number of content arguments (" << i << ")";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
593
          throwError(ERROR_ENTRY_COUNT_MISMATCH, lMsg.str().c_str());
42.1.6 by luisrod
- Added ability to create directories
594
        }
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
595
      }
596
597
      const ArchiveEntry& lEntry = aEntries[i];
28 by Juan Zacarias
Implemented the add in the archive update function
598
      
599
      compress(lEntry, lFile);
600
    
601
    }
602
603
    if (aFiles->next(lFile))
604
    {
605
      std::ostringstream lMsg;
606
      lMsg << "number of entries (" << aEntries.size()
607
        << ") less than number of content arguments";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
608
      throwError(ERROR_ENTRY_COUNT_MISMATCH, lMsg.str().c_str());
28 by Juan Zacarias
Implemented the add in the archive update function
609
    }
610
611
    aFiles->close();
612
  }
613
614
  void ArchiveFunction::ArchiveCompressor::compress(const ArchiveEntry& aEntry, Item aFile)
615
  {
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
616
      std::istream* lStream;
617
      bool lDeleteStream;
618
      uint64_t lFileSize;
619
28 by Juan Zacarias
Implemented the add in the archive update function
620
      archive_entry_set_pathname(theEntry, aEntry.getEntryPath().c_str());
621
      archive_entry_set_mtime(theEntry, aEntry.getLastModified(), 0);
42.1.6 by luisrod
- Added ability to create directories
622
      if(aEntry.getEntryType() == ArchiveEntry::regular){
623
        archive_entry_set_filetype(theEntry, AE_IFREG);
624
        lDeleteStream = getStream(
625
          aEntry, aFile, lStream, lFileSize);
626
      } else {
627
        archive_entry_set_filetype(theEntry, AE_IFDIR);
628
        lDeleteStream = false;
629
        lFileSize = 0;
630
      }
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
631
      // TODO: specifies the permits of a file
632
      archive_entry_set_perm(theEntry, 0644);
633
      archive_entry_set_size(theEntry, lFileSize);
634
35 by Matthias Brantner
- reworked the way options are passed and named
635
      if (theOptions.getFormat() == "ZIP")
636
      {
637
        int lNextComp;
638
        std::string lNextCompString;
639
        if (aEntry.getCompression().length() > 0)
640
        {
641
          lNextCompString = aEntry.getCompression().c_str();
642
          lNextComp = compressionCode(lNextCompString);
643
#ifndef ZORBA_LIBARCHIVE_HAVE_SET_COMPRESSION
644
          std::ostringstream lMsg;
645
          lMsg << lNextCompString << ": setting different compression algorithms for each entry is not supported by the used version of libarchive";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
646
          throwError(ERROR_DIFFERENT_COMPRESSIONS_NOT_SUPPORTED, lMsg.str().c_str());
35 by Matthias Brantner
- reworked the way options are passed and named
647
#endif
648
        }
649
        else
650
        {
651
          lNextCompString = theOptions.getCompression();
652
          lNextComp = compressionCode(lNextCompString);
653
        }
37 by Matthias Brantner
fix if libarchive is not patched
654
        if (lNextComp < ZORBA_ARCHIVE_COMPRESSION_DEFLATE && lNextComp != ARCHIVE_COMPRESSION_NONE)
35 by Matthias Brantner
- reworked the way options are passed and named
655
        {
656
          std::ostringstream lMsg;
657
          lMsg << lNextCompString << ": compression algorithm not supported for ZIP format (required: deflate, store)";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
658
          throwError(ERROR_INVALID_OPTIONS, lMsg.str().c_str());
35 by Matthias Brantner
- reworked the way options are passed and named
659
        }
660
661
#ifdef ZORBA_LIBARCHIVE_HAVE_SET_COMPRESSION
662
        setArchiveCompression(theArchive, lNextComp);
663
#endif
664
      }
36 by Matthias Brantner
better errors + removed support for exotic formats and compressions
665
      else
666
      {
667
        if (aEntry.getCompression().length() > 0)
668
        {
669
          std::ostringstream lMsg;
670
          lMsg << aEntry.getCompression() << ": compression attribute only allowed for zip format";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
671
          throwError(ERROR_DIFFERENT_COMPRESSIONS_NOT_SUPPORTED, lMsg.str().c_str());
36 by Matthias Brantner
better errors + removed support for exotic formats and compressions
672
        }
673
      }
35 by Matthias Brantner
- reworked the way options are passed and named
674
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
675
      archive_write_header(theArchive, theEntry);
676
42.1.6 by luisrod
- Added ability to create directories
677
      if(aEntry.getEntryType() == ArchiveEntry::regular)
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
678
      {
42.1.6 by luisrod
- Added ability to create directories
679
        char lBuf[ZORBA_ARCHIVE_MAX_READ_BUF];
680
        while (lStream->good())
681
        {
682
          lStream->read(lBuf, ZORBA_ARCHIVE_MAX_READ_BUF);
683
          archive_write_data(theArchive, lBuf, lStream->gcount());
684
        }
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
685
      }
686
687
      archive_entry_clear(theEntry);
688
      archive_write_finish_entry(theArchive);
689
690
      if (lDeleteStream)
691
      {
692
        delete lStream;
693
        lStream = 0;
694
      }
695
  }
696
697
  void
698
  ArchiveFunction::ArchiveCompressor::close()
699
  {
700
	  archive_write_close(theArchive);
701
	  archive_write_finish(theArchive);
702
  }
703
704
  std::stringstream*
705
  ArchiveFunction::ArchiveCompressor::getResultStream()
706
  {
707
    return theStream;
708
  }
709
710
15 by Juan Zacarias
Partial implementation of create function
711
  String 
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
712
  ArchiveFunction::getURI() const
15 by Juan Zacarias
Partial implementation of create function
713
  {
714
    return theModule->getURI();
7 by Matthias Brantner
fixed two build problems:
715
  }
716
717
  void
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
718
  ArchiveFunction::throwError(
9 by Matthias Brantner
- introduced a schema for entries and options
719
        const char* aLocalName,
720
        const char* aErrorMessage)
7 by Matthias Brantner
fixed two build problems:
721
  {
9 by Matthias Brantner
- introduced a schema for entries and options
722
    String errNS(ArchiveModule::getModuleURI());
723
    Item errQName = ArchiveModule::getItemFactory()->createQName(
724
        errNS, aLocalName);
725
    throw USER_EXCEPTION(errQName, aErrorMessage);
5 by Juan Zacarias
Changed name to archive module
726
  }
727
9 by Matthias Brantner
- introduced a schema for entries and options
728
  void
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
729
  ArchiveFunction::checkForError(
9 by Matthias Brantner
- introduced a schema for entries and options
730
        int aErrNo,
731
        const char* aLocalName,
732
        struct archive *a)
5 by Juan Zacarias
Changed name to archive module
733
  {
9 by Matthias Brantner
- introduced a schema for entries and options
734
    if (aErrNo != ARCHIVE_OK)
5 by Juan Zacarias
Changed name to archive module
735
    {
9 by Matthias Brantner
- introduced a schema for entries and options
736
      if (!aLocalName)
737
      {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
738
        throwError(ERROR_CORRUPTED_ARCHIVE, archive_error_string(a));
9 by Matthias Brantner
- introduced a schema for entries and options
739
      }
740
      else
741
      {
742
        throwError(aLocalName, archive_error_string(a));
743
      }
5 by Juan Zacarias
Changed name to archive module
744
    }
9 by Matthias Brantner
- introduced a schema for entries and options
745
  }
746
747
  zorba::Item
748
  ArchiveFunction::getOneItem(const Arguments_t& aArgs, int aIndex)
749
  {
750
    Item lItem;
751
    Iterator_t args_iter = aArgs[aIndex]->getIterator();
752
    args_iter->open();
753
    args_iter->next(lItem);
754
    args_iter->close();
755
756
    return lItem;
757
  }
758
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
759
  std::string
760
  ArchiveFunction::formatName(int f)
761
  {
762
    // first 16 bit indicate the format family
763
    switch (f & ARCHIVE_FORMAT_BASE_MASK)
764
    {
765
      case ARCHIVE_FORMAT_TAR: return "TAR";
766
      case ARCHIVE_FORMAT_ZIP: return "ZIP";
767
      default: return "";
768
    }
769
  }
770
771
  std::string
772
  ArchiveFunction::compressionName(int c)
773
  {
774
    switch (c)
775
    {
776
      case ARCHIVE_COMPRESSION_NONE: return "NONE";
35 by Matthias Brantner
- reworked the way options are passed and named
777
      case ZORBA_ARCHIVE_COMPRESSION_DEFLATE: return "DEFLATE";
778
      case ZORBA_ARCHIVE_COMPRESSION_STORE: return "STORE";
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
779
      case ARCHIVE_COMPRESSION_GZIP: return "GZIP";
780
      case ARCHIVE_COMPRESSION_BZIP2: return "BZIP2";
781
      case ARCHIVE_COMPRESSION_LZMA: return "LZMA";
782
      default: return "";
783
    }
784
  }
785
19 by Matthias Brantner
support for create options
786
  int
787
  ArchiveFunction::formatCode(const std::string& f)
788
  {
36 by Matthias Brantner
better errors + removed support for exotic formats and compressions
789
    if (f == "TAR")
19 by Matthias Brantner
support for create options
790
    {
21 by Matthias Brantner
- case insensitive entry and format options
791
      return ARCHIVE_FORMAT_TAR_USTAR;
19 by Matthias Brantner
support for create options
792
    }
793
    else if (f == "ZIP")
794
    {
795
      return ARCHIVE_FORMAT_ZIP;
796
    }
797
    else
798
    {
799
      std::ostringstream lMsg;
800
      lMsg << f << ": archive format not supported";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
801
      throwError(ERROR_INVALID_OPTIONS, lMsg.str().c_str());
19 by Matthias Brantner
support for create options
802
    }
803
    return 0;
804
  }
805
806
  int
807
  ArchiveFunction::compressionCode(const std::string& c)
808
  {
809
    if (c == "NONE")
810
    {
811
      return ARCHIVE_COMPRESSION_NONE;
812
    }
42 by Matthias Brantner
- new option skip-extra-attrs (same effect as zip -X) but needs a special version of libarchive
813
    else if (c == "STORE")
35 by Matthias Brantner
- reworked the way options are passed and named
814
    {
815
      return ZORBA_ARCHIVE_COMPRESSION_STORE;
816
    }
42 by Matthias Brantner
- new option skip-extra-attrs (same effect as zip -X) but needs a special version of libarchive
817
    else if (c == "DEFLATE")
35 by Matthias Brantner
- reworked the way options are passed and named
818
    {
819
      return ZORBA_ARCHIVE_COMPRESSION_DEFLATE;
820
    }
19 by Matthias Brantner
support for create options
821
    else if (c == "GZIP")
822
    {
823
      return ARCHIVE_COMPRESSION_GZIP;
824
    }
825
    else if (c == "BZIP2")
826
    {
827
      return ARCHIVE_COMPRESSION_BZIP2;
828
    }
829
    else if (c == "LZMA")
830
    {
831
      return ARCHIVE_COMPRESSION_LZMA;
832
    }
833
    else
834
    {
835
      std::ostringstream lMsg;
836
      lMsg << c << ": compression algorithm not supported";
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
837
      throwError(ERROR_INVALID_OPTIONS, lMsg.str().c_str());
19 by Matthias Brantner
support for create options
838
    }
839
    return 0;
840
  }
841
842
  void
843
  ArchiveFunction::setArchiveCompression(struct archive* a, int c)
844
  {
21 by Matthias Brantner
- case insensitive entry and format options
845
    int lErr = 0;
19 by Matthias Brantner
support for create options
846
    switch (c)
847
    {
35 by Matthias Brantner
- reworked the way options are passed and named
848
#ifdef ZORBA_LIBARCHIVE_HAVE_SET_COMPRESSION
849
      case ZORBA_ARCHIVE_COMPRESSION_STORE:
850
        lErr = archive_write_zip_set_compression_store(a); break;
851
      case ZORBA_ARCHIVE_COMPRESSION_DEFLATE:
852
      case ARCHIVE_COMPRESSION_NONE:
853
        lErr = archive_write_zip_set_compression_deflate(a); break;
854
#else
855
      case ZORBA_ARCHIVE_COMPRESSION_STORE:
38 by Matthias Brantner
renamed module:
856
        archive_write_set_options(a, "zip:compression=store");
35 by Matthias Brantner
- reworked the way options are passed and named
857
        break;
858
      case ZORBA_ARCHIVE_COMPRESSION_DEFLATE:
38 by Matthias Brantner
renamed module:
859
        archive_write_set_options(a, "zip:compression=deflate");
35 by Matthias Brantner
- reworked the way options are passed and named
860
        break;
19 by Matthias Brantner
support for create options
861
      case ARCHIVE_COMPRESSION_NONE:
21 by Matthias Brantner
- case insensitive entry and format options
862
        lErr = archive_write_set_compression_none(a); break;
35 by Matthias Brantner
- reworked the way options are passed and named
863
#endif
19 by Matthias Brantner
support for create options
864
      case ARCHIVE_COMPRESSION_GZIP:
21 by Matthias Brantner
- case insensitive entry and format options
865
        lErr = archive_write_set_compression_gzip(a); break;
19 by Matthias Brantner
support for create options
866
      case ARCHIVE_COMPRESSION_BZIP2:
21 by Matthias Brantner
- case insensitive entry and format options
867
        lErr = archive_write_set_compression_bzip2(a); break;
19 by Matthias Brantner
support for create options
868
      case ARCHIVE_COMPRESSION_LZMA:
21 by Matthias Brantner
- case insensitive entry and format options
869
        lErr = archive_write_set_compression_lzma(a); break;
19 by Matthias Brantner
support for create options
870
      default: assert(false);
871
    }
21 by Matthias Brantner
- case insensitive entry and format options
872
    ArchiveFunction::checkForError(lErr, 0, a);
19 by Matthias Brantner
support for create options
873
  }
874
9 by Matthias Brantner
- introduced a schema for entries and options
875
#ifdef WIN32
876
  long
877
#else
878
  ssize_t
879
#endif    
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
880
  ArchiveItemSequence::readStream(struct archive*, void *data, const void **buff)
9 by Matthias Brantner
- introduced a schema for entries and options
881
  {
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
882
    ArchiveItemSequence::CallbackData* lData =
883
      reinterpret_cast<ArchiveItemSequence::CallbackData*>(data);
9 by Matthias Brantner
- introduced a schema for entries and options
884
14 by Matthias Brantner
make sure that multiple xquery functions accessing the same zip file works
885
    if (lData->theEnd) return 0;
886
9 by Matthias Brantner
- introduced a schema for entries and options
887
    std::istream* lStream = lData->theStream;
888
14 by Matthias Brantner
make sure that multiple xquery functions accessing the same zip file works
889
    // seek to where we left of
890
    if (lData->theSeekable) lStream->seekg(lData->thePos, std::ios::beg);
891
9 by Matthias Brantner
- introduced a schema for entries and options
892
    lStream->read(lData->theBuffer, ZORBA_ARCHIVE_MAX_READ_BUF);
893
    *buff = lData->theBuffer;
894
14 by Matthias Brantner
make sure that multiple xquery functions accessing the same zip file works
895
    if (lStream->eof()) lData->theEnd = true;
896
897
    // remember the stream pos before leaving the function
898
    if (lData->theSeekable) lData->thePos = lStream->tellg();
899
9 by Matthias Brantner
- introduced a schema for entries and options
900
    return lStream->gcount(); 
901
  }
902
22 by Matthias Brantner
- properly handle base64 values
903
  ArchiveItemSequence::ArchiveIterator::ArchiveIterator(zorba::Item& a)
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
904
    : theArchiveItem(a),
905
      theArchive(0),
906
      theFactory(Zorba::getInstance(0)->getItemFactory())
907
  {}
908
909
  void
910
  ArchiveItemSequence::ArchiveIterator::open()
911
  {
912
    // open archive and allow for all kinds of formats and compression algos
913
    theArchive = archive_read_new();
914
915
    if (!theArchive)
916
      ArchiveFunction::throwError(
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
917
          ERROR_CORRUPTED_ARCHIVE, "internal error (couldn't create archive)");
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
918
919
	  int lErr = archive_read_support_compression_all(theArchive);
920
    ArchiveFunction::checkForError(lErr, 0, theArchive);
921
922
	  archive_read_support_format_all(theArchive);
923
    ArchiveFunction::checkForError(lErr, 0, theArchive);
924
925
    if (theArchiveItem.isStreamable())
926
    {
927
      theData.theStream = &theArchiveItem.getStream();
14 by Matthias Brantner
make sure that multiple xquery functions accessing the same zip file works
928
      theData.theStream->clear();
929
      theData.theSeekable = theArchiveItem.isSeekable();
930
      theData.theEnd = false;
931
      theData.thePos = 0;
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
932
22 by Matthias Brantner
- properly handle base64 values
933
      if (theArchiveItem.isEncoded())
934
      {
935
        base64::attach(*theData.theStream);
936
      }
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
937
45.1.1 by Luis Rodriguez Gonzalez
-Replaced open functions with old ones to make it work with Macports
938
      lErr = archive_read_open(theArchive, &theData, NULL, ArchiveItemSequence::readStream, NULL);
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
939
      ArchiveFunction::checkForError(lErr, 0, theArchive);
940
    }
941
    else
942
    {
943
      size_t lLen = 0;
22 by Matthias Brantner
- properly handle base64 values
944
      char* lData = const_cast<char*>(
945
          theArchiveItem.getBase64BinaryValue(lLen));
946
947
      if (theArchiveItem.isEncoded())
948
      {
949
        zorba::String lEncoded(lData, lLen); 
48 by Paul J. Lucas
Include file clean-up.
950
        theDecodedData = base64::decode(lEncoded);
22 by Matthias Brantner
- properly handle base64 values
951
        lLen = theDecodedData.size();
952
        lErr = archive_read_open_memory(theArchive,
953
            const_cast<char*>(theDecodedData.c_str()), lLen);
954
        ArchiveFunction::checkForError(lErr, 0, theArchive);
955
      }
956
      else
957
      {
958
        lErr = archive_read_open_memory(theArchive, lData, lLen);
959
        ArchiveFunction::checkForError(lErr, 0, theArchive);
960
      }
961
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
962
    }
963
  }
964
965
  void
966
  ArchiveItemSequence::ArchiveIterator::close()
967
  {
968
    int lErr = archive_read_finish(theArchive);
969
    ArchiveFunction::checkForError(lErr, 0, theArchive);
970
    theArchive = 0;
971
  }
9 by Matthias Brantner
- introduced a schema for entries and options
972
15 by Juan Zacarias
Partial implementation of create function
973
#ifdef WIN32
974
  long
975
#else
976
  ssize_t
977
#endif
17 by Matthias Brantner
first very basic version of create#2 and #3
978
  ArchiveFunction::writeStream(
979
      struct archive *,
980
      void *func,
981
      const void *buff,
982
      size_t n)
15 by Juan Zacarias
Partial implementation of create function
983
  {
28 by Juan Zacarias
Implemented the add in the archive update function
984
    ArchiveFunction::ArchiveCompressor* lFunc =
985
      static_cast<ArchiveFunction::ArchiveCompressor*>(func);
15 by Juan Zacarias
Partial implementation of create function
986
17 by Matthias Brantner
first very basic version of create#2 and #3
987
    const char * lBuf = static_cast<const char *>(buff);
22 by Matthias Brantner
- properly handle base64 values
988
    lFunc->getResultStream()->write(lBuf, n);
15 by Juan Zacarias
Partial implementation of create function
989
  
990
    return n;
991
  }
992
17 by Matthias Brantner
first very basic version of create#2 and #3
993
/*******************************************************************************
994
 ******************************************************************************/
5 by Juan Zacarias
Changed name to archive module
995
  zorba::ItemSequence_t
996
    CreateFunction::evaluate(
997
      const Arguments_t& aArgs,
998
      const zorba::StaticContext* aSctx,
999
      const zorba::DynamicContext* aDctx) const 
1000
  {
17 by Matthias Brantner
first very basic version of create#2 and #3
1001
    std::vector<ArchiveEntry> lEntries;
1002
1003
    {
1004
      Iterator_t lEntriesIter = aArgs[0]->getIterator();
1005
1006
      zorba::Item lEntry;
1007
      lEntriesIter->open();
1008
      while (lEntriesIter->next(lEntry))
1009
      {
1010
        lEntries.resize(lEntries.size() + 1);
1011
        lEntries.back().setValues(lEntry);
1012
      }
1013
      lEntriesIter->close();
1014
    }
1015
1016
    ArchiveOptions lOptions;
1017
1018
    if (aArgs.size() == 3)
1019
    {
1020
      zorba::Item lOptionsItem = getOneItem(aArgs, 2);
1021
      lOptions.setValues(lOptionsItem);
1022
    }
1023
    
1024
    ArchiveCompressor lArchive;
1025
      
1026
    zorba::Iterator_t lFileIter = aArgs[1]->getIterator();
23.2.1 by Juan Zacarias
changed ArchiveCompressor's namespace to ArchiveFunction
1027
    lArchive.open(lOptions);
1028
    lArchive.compress(lEntries, lFileIter);
1029
    lArchive.close();
17 by Matthias Brantner
first very basic version of create#2 and #3
1030
1031
    zorba::Item lRes = theModule->getItemFactory()->
1032
      createStreamableBase64Binary(
22 by Matthias Brantner
- properly handle base64 values
1033
        *lArchive.getResultStream(),
28 by Juan Zacarias
Implemented the add in the archive update function
1034
        &(ArchiveFunction::ArchiveCompressor::releaseStream),
17 by Matthias Brantner
first very basic version of create#2 and #3
1035
        true, // seekable
1036
        false // not encoded
1037
        );
1038
    return ItemSequence_t(new SingletonItemSequence(lRes));
7 by Matthias Brantner
fixed two build problems:
1039
  }
1040
15 by Juan Zacarias
Partial implementation of create function
1041
22 by Matthias Brantner
- properly handle base64 values
1042
/*******************************************************************************
1043
 ******************************************************************************/
5 by Juan Zacarias
Changed name to archive module
1044
  zorba::ItemSequence_t
8 by Matthias Brantner
streaming archive:entries
1045
  EntriesFunction::evaluate(
1046
    const Arguments_t& aArgs,
1047
    const zorba::StaticContext* aSctx,
1048
    const zorba::DynamicContext* aDctx) const 
5 by Juan Zacarias
Changed name to archive module
1049
  { 
9 by Matthias Brantner
- introduced a schema for entries and options
1050
    Item lArchive = getOneItem(aArgs, 0);
8 by Matthias Brantner
streaming archive:entries
1051
    
1052
    return ItemSequence_t(new EntriesItemSequence(lArchive));
1053
  }
1054
1055
  EntriesFunction::EntriesItemSequence::EntriesIterator::EntriesIterator(
1056
      zorba::Item& aArchive)
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1057
    : ArchiveIterator(aArchive)
8 by Matthias Brantner
streaming archive:entries
1058
  {
53 by Luis Rodriguez Gonzalez
All comments fixed
1059
      gNameKey = theFactory->createString(NAME_KEY_NAME);
1060
      gTypeKey = theFactory->createString(TYPE_KEY_NAME);
1061
      gSizeKey = theFactory->createString(SIZE_KEY_NAME);
1062
      gLastModifiedKey = theFactory->createString(LAST_MODIFIED_KEY_NAME);
8 by Matthias Brantner
streaming archive:entries
1063
  }
1064
1065
  bool
9 by Matthias Brantner
- introduced a schema for entries and options
1066
  EntriesFunction::EntriesItemSequence::EntriesIterator::next(zorba::Item& aRes)
8 by Matthias Brantner
streaming archive:entries
1067
  {
1068
    struct archive_entry *lEntry;
1069
9 by Matthias Brantner
- introduced a schema for entries and options
1070
    int lErr = archive_read_next_header(theArchive, &lEntry);
1071
    
1072
    if (lErr == ARCHIVE_EOF) return false;
1073
1074
    if (lErr != ARCHIVE_OK)
8 by Matthias Brantner
streaming archive:entries
1075
    {
9 by Matthias Brantner
- introduced a schema for entries and options
1076
      ArchiveFunction::checkForError(lErr, 0, theArchive);
8 by Matthias Brantner
streaming archive:entries
1077
    }
1078
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1079
    std::vector<std::pair<zorba::Item, zorba::Item> > lObjectArray;
1080
    std::pair<zorba::Item, zorba::Item> lElemPair;
1081
9 by Matthias Brantner
- introduced a schema for entries and options
1082
    // create text content (i.e. path name)
8 by Matthias Brantner
streaming archive:entries
1083
    String lName = archive_entry_pathname(lEntry);
53 by Luis Rodriguez Gonzalez
All comments fixed
1084
    lElemPair = std::make_pair<zorba::Item, zorba::Item>(gNameKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1085
                                                         theFactory->createString(lName));
1086
    lObjectArray.push_back(lElemPair);
9 by Matthias Brantner
- introduced a schema for entries and options
1087
1088
    // create size attr if the value is set in the archive
1089
    if (archive_entry_size_is_set(lEntry))
1090
    {
1091
      long long lSize = archive_entry_size(lEntry);
53 by Luis Rodriguez Gonzalez
All comments fixed
1092
      lElemPair = std::make_pair<zorba::Item, zorba::Item>(gSizeKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1093
                                                           theFactory->createInteger(lSize));
1094
      lObjectArray.push_back(lElemPair);
9 by Matthias Brantner
- introduced a schema for entries and options
1095
    }
1096
1097
    // create last-modified attr if the value is set in the archive
1098
    if (archive_entry_mtime_is_set(lEntry))
1099
    {
1100
      time_t lTime = archive_entry_mtime(lEntry);
53 by Luis Rodriguez Gonzalez
All comments fixed
1101
      lElemPair = std::make_pair<zorba::Item, zorba::Item>(gLastModifiedKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1102
                                                           ArchiveModule::createDateTimeItem(lTime));
1103
      lObjectArray.push_back(lElemPair);
9 by Matthias Brantner
- introduced a schema for entries and options
1104
    }
1105
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1106
    std::string lEntryType;
42.1.6 by luisrod
- Added ability to create directories
1107
    if(archive_entry_filetype(lEntry) == AE_IFDIR)
1108
    {
1109
      // this entry is a directory
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1110
      lEntryType = "directory";
42.1.6 by luisrod
- Added ability to create directories
1111
    }
1112
    else if(archive_entry_filetype(lEntry) == AE_IFREG)
1113
    {
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1114
      lEntryType = "regular";
42.1.6 by luisrod
- Added ability to create directories
1115
    }
1116
    else
1117
    {
1118
      // error! type not supported!
1119
      // for the time being don't do anything
1120
    }
1121
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1122
    //lMemberName = theFactory->createString("type");
53 by Luis Rodriguez Gonzalez
All comments fixed
1123
    lElemPair = std::make_pair<zorba::Item, zorba::Item>(gTypeKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1124
                                                         theFactory->createString(lEntryType));
1125
    lObjectArray.push_back(lElemPair);
42.1.6 by luisrod
- Added ability to create directories
1126
9 by Matthias Brantner
- introduced a schema for entries and options
1127
    // skip to the next entry and raise an error if that fails
1128
    lErr = archive_read_data_skip(theArchive);
1129
    ArchiveFunction::checkForError(lErr, 0, theArchive);
8 by Matthias Brantner
streaming archive:entries
1130
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1131
    aRes = theFactory->createJSONObject(lObjectArray);
1132
8 by Matthias Brantner
streaming archive:entries
1133
    return true;
1134
  }
1135
12 by Matthias Brantner
extract-text#2 and extract-text#3
1136
/*******************************************************************************
1137
 ******************************************************************************/
27.1.1 by luisrod
- a:delete() added
1138
1139
 /*******************************************************************************
1140
 *  This function is meant to replace all the look for specific headers that are
1141
 *  or are not in a list (ArchiveEntrySet)
1142
 ******************************************************************************/
1143
  struct archive_entry*
35 by Matthias Brantner
- reworked the way options are passed and named
1144
    ExtractFunction::ExtractItemSequence::ExtractIterator::lookForHeader(
1145
        bool aMatch,
1146
        ArchiveOptions* aOptions)
27.1.1 by luisrod
- a:delete() added
1147
  {
30.1.1 by Matthias Brantner
- fixed a memory leak in the update and delete functions
1148
    struct archive_entry *lEntry = 0;
27.1.1 by luisrod
- a:delete() added
1149
1150
    while (true)
1151
    {
1152
      int lErr = archive_read_next_header(theArchive, &lEntry);
1153
      
1154
      if (lErr == ARCHIVE_EOF) return NULL;
1155
1156
      if (lErr != ARCHIVE_OK)
1157
      {
1158
        ArchiveFunction::checkForError(lErr, 0, theArchive);
1159
      }
1160
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1161
      if(aOptions)
1162
        aOptions->setValues(theArchive);
1163
27.1.1 by luisrod
- a:delete() added
1164
      if (theReturnAll) break;
1165
1166
      String lName = archive_entry_pathname(lEntry);
1167
      if(aMatch) {
30 by Juan Zacarias
Added Delete Function
1168
        if (theEntryNames.find(lName.str()) != theEntryNames.end())
27.1.1 by luisrod
- a:delete() added
1169
        {
1170
          break;
1171
        }
1172
      } else {
30 by Juan Zacarias
Added Delete Function
1173
        if (theEntryNames.find(lName.str()) == theEntryNames.end())
27.1.1 by luisrod
- a:delete() added
1174
        {
1175
          break;
1176
        }
1177
      }
1178
    }
1179
1180
    return lEntry;
1181
  }
1182
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1183
  zorba::ItemSequence_t
1184
  ExtractTextFunction::evaluate(
1185
    const Arguments_t& aArgs,
1186
    const zorba::StaticContext* aSctx,
1187
    const zorba::DynamicContext* aDctx) const 
1188
  { 
1189
    Item lArchive = getOneItem(aArgs, 0);
12 by Matthias Brantner
extract-text#2 and extract-text#3
1190
1191
    zorba::String lEncoding("UTF-8");
1192
    if (aArgs.size() == 3)
1193
    {
1194
      zorba::Item lItem = getOneItem(aArgs, 2);
1195
      lEncoding = lItem.getStringValue();
1196
      if (!transcode::is_supported(lEncoding.c_str()))
1197
      {
1198
        std::ostringstream lMsg;
1199
        lMsg << lEncoding << ": unsupported encoding";
1200
          
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1201
        throwError(ERROR_INVALID_ENCODING, lMsg.str().c_str());
12 by Matthias Brantner
extract-text#2 and extract-text#3
1202
      }
1203
    }
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1204
    
12 by Matthias Brantner
extract-text#2 and extract-text#3
1205
    // return all entries if no second arg is given
1206
    bool lReturnAll = aArgs.size() == 1;
1207
1208
    std::auto_ptr<ExtractItemSequence> lSeq(
14.1.1 by Matthias Brantner
extract-binary
1209
        new ExtractTextItemSequence(lArchive, lReturnAll, lEncoding));
12 by Matthias Brantner
extract-text#2 and extract-text#3
1210
1211
    // get the names of all entries that should be retruned
1212
    if (aArgs.size() > 1)
1213
    {
14.1.1 by Matthias Brantner
extract-binary
1214
      ExtractFunction::ExtractItemSequence::EntryNameSet& lSet
1215
        = lSeq->getNameSet();
12 by Matthias Brantner
extract-text#2 and extract-text#3
1216
1217
      zorba::Item lItem;
1218
      Iterator_t lIter = aArgs[1]->getIterator();
1219
      lIter->open();
1220
      while (lIter->next(lItem))
1221
      {
30 by Juan Zacarias
Added Delete Function
1222
        lSet.insert(lItem.getStringValue().str());
12 by Matthias Brantner
extract-text#2 and extract-text#3
1223
      }
1224
1225
      lIter->close();
1226
    }
1227
1228
    return ItemSequence_t(lSeq.release());
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1229
  }
1230
8 by Matthias Brantner
streaming archive:entries
1231
  bool
14.1.1 by Matthias Brantner
extract-binary
1232
  ExtractTextFunction::ExtractTextItemSequence::ExtractTextIterator::next(
12 by Matthias Brantner
extract-text#2 and extract-text#3
1233
      zorba::Item& aRes)
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1234
  {
27.1.1 by luisrod
- a:delete() added
1235
    struct archive_entry *lEntry = lookForHeader(true);
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1236
30 by Juan Zacarias
Added Delete Function
1237
    //NULL is EOF
1238
    if (!lEntry)
1239
      return false;
1240
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1241
    String lResult;
1242
1243
    // reserve some space if we know the decompressed size
1244
    if (archive_entry_size_is_set(lEntry))
1245
    {
1246
      long long lSize = archive_entry_size(lEntry);
1247
      lResult.reserve(lSize);
1248
    }
1249
1250
    char lBuf[ZORBA_ARCHIVE_MAX_READ_BUF];
1251
1252
    // read entire entry into a string
1253
    while (true)
1254
    {
14 by Matthias Brantner
make sure that multiple xquery functions accessing the same zip file works
1255
      int s = archive_read_data(
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1256
          theArchive, &lBuf, ZORBA_ARCHIVE_MAX_READ_BUF);
1257
1258
      if (s == 0) break;
1259
1260
      lResult.append(lBuf, s);
1261
    }
1262
12 by Matthias Brantner
extract-text#2 and extract-text#3
1263
    if (transcode::is_necessary(theEncoding.c_str()))
1264
    {
1265
      zorba::String lTranscodedString;
1266
      transcode::stream<std::istringstream> lTranscoder(
1267
          theEncoding.c_str(),
1268
          lResult.c_str()
1269
        );
1270
      char buf[1024];
1271
      while (lTranscoder.good())
1272
      {
1273
        lTranscoder.read(buf, 1024);
1274
        lTranscodedString.append(buf, lTranscoder.gcount());
1275
      }
1276
      aRes = theFactory->createString(lTranscodedString);
1277
    }
1278
    else
1279
    {
1280
      aRes = theFactory->createString(lResult);
1281
    }
11 by Matthias Brantner
- extract-text#1 function (without transcoding)
1282
1283
    return true;
7 by Matthias Brantner
fixed two build problems:
1284
  }
1285
14.1.1 by Matthias Brantner
extract-binary
1286
/*******************************************************************************
1287
 ******************************************************************************/
5 by Juan Zacarias
Changed name to archive module
1288
  zorba::ItemSequence_t
1289
    ExtractBinaryFunction::evaluate(
1290
      const Arguments_t& aArgs,
1291
      const zorba::StaticContext* aSctx,
1292
      const zorba::DynamicContext* aDctx) const 
1293
  {
14.1.1 by Matthias Brantner
extract-binary
1294
    Item lArchive = getOneItem(aArgs, 0);
1295
1296
    // return all entries if no second arg is given
1297
    bool lReturnAll = aArgs.size() == 1;
1298
1299
    std::auto_ptr<ExtractItemSequence> lSeq(
1300
        new ExtractBinaryItemSequence(lArchive, lReturnAll));
1301
1302
    // get the names of all entries that should be retruned
1303
    if (aArgs.size() > 1)
1304
    {
1305
      ExtractFunction::ExtractItemSequence::EntryNameSet& lSet
1306
        = lSeq->getNameSet();
1307
1308
      zorba::Item lItem;
1309
      Iterator_t lIter = aArgs[1]->getIterator();
1310
      lIter->open();
1311
      while (lIter->next(lItem))
1312
      {
30 by Juan Zacarias
Added Delete Function
1313
        lSet.insert(lItem.getStringValue().str());
14.1.1 by Matthias Brantner
extract-binary
1314
      }
1315
1316
      lIter->close();
1317
    }
1318
1319
    return ItemSequence_t(lSeq.release());
1320
  }
1321
1322
  bool
1323
  ExtractBinaryFunction::ExtractBinaryItemSequence::ExtractBinaryIterator::next(
1324
      zorba::Item& aRes)
1325
  {
27.1.1 by luisrod
- a:delete() added
1326
    struct archive_entry *lEntry = lookForHeader(true);
14.1.1 by Matthias Brantner
extract-binary
1327
30 by Juan Zacarias
Added Delete Function
1328
    //NULL is EOF
1329
    if (!lEntry)
1330
      return false;
1331
    
14.1.1 by Matthias Brantner
extract-binary
1332
    std::vector<unsigned char> lResult;
1333
1334
    // reserve some space if we know the decompressed size
1335
    if (archive_entry_size_is_set(lEntry))
1336
    {
1337
      long long lSize = archive_entry_size(lEntry);
1338
      lResult.reserve(lSize);
1339
    }
1340
1341
    std::vector<unsigned char> lBuf;
1342
    lBuf.resize(ZORBA_ARCHIVE_MAX_READ_BUF);
1343
1344
    // read entire entry into a string
1345
    while (true)
1346
    {
1347
      int s = archive_read_data(
1348
          theArchive, &lBuf[0], ZORBA_ARCHIVE_MAX_READ_BUF);
1349
1350
      if (s == 0) break;
1351
1352
      lResult.insert(lResult.end(), lBuf.begin(), lBuf.begin() + s);
1353
    }
1354
49.1.1 by Paul J. Lucas
Fixes.
1355
    aRes = theFactory->createBase64Binary(reinterpret_cast<char const*>(&lResult[0]), lResult.size(), false);
14.1.1 by Matthias Brantner
extract-binary
1356
1357
    return true;
7 by Matthias Brantner
fixed two build problems:
1358
  }
1359
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1360
1361
/*******************************************************************************
1362
 ******************************************************************************/
1363
  zorba::ItemSequence_t
1364
    OptionsFunction::evaluate(
1365
      const Arguments_t& aArgs,
1366
      const zorba::StaticContext* aSctx,
1367
      const zorba::DynamicContext* aDctx) const 
1368
  {
1369
    Item lArchive = getOneItem(aArgs, 0);
1370
1371
    return ItemSequence_t(new OptionsItemSequence(lArchive));
1372
  }
1373
53 by Luis Rodriguez Gonzalez
All comments fixed
1374
  OptionsFunction::OptionsItemSequence::OptionsIterator::OptionsIterator(Item &aArchive)
1375
      :ArchiveIterator(aArchive)
1376
  {
1377
      gFormatKey = theFactory->createString(FORMAT_KEY_NAME);
1378
      gCompressionKey = theFactory->createString(COMPRESSION_KEY_NAME);
1379
  }
1380
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1381
  bool
1382
  OptionsFunction::OptionsItemSequence::OptionsIterator::next(
1383
      zorba::Item& aRes)
1384
  {
1385
    if (lExhausted) return false;
1386
1387
    lExhausted = true;
1388
1389
    struct archive_entry *lEntry;
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1390
    typedef std::pair<zorba::Item, zorba::Item> tArrElemt;
1391
    tArrElemt lElemt;
1392
    std::vector<tArrElemt> lJSONObject;
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1393
1394
    // to get the format, we need to peek into the first header
1395
    int lErr = archive_read_next_header(theArchive, &lEntry);
1396
1397
    if (lErr != ARCHIVE_OK && lErr != ARCHIVE_EOF)
1398
    {
1399
      ArchiveFunction::checkForError(lErr, 0, theArchive);
1400
    }
1401
1402
    std::string lFormat =
1403
      ArchiveFunction::formatName(archive_format(theArchive));
35 by Matthias Brantner
- reworked the way options are passed and named
1404
    std::string lCompression =
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1405
      ArchiveFunction::compressionName(archive_compression(theArchive));
1406
1407
    if (lFormat == "ZIP")
1408
    {
35 by Matthias Brantner
- reworked the way options are passed and named
1409
      lCompression = "DEFLATE";
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1410
    }
1411
53 by Luis Rodriguez Gonzalez
All comments fixed
1412
    lElemt = std::make_pair<zorba::Item, zorba::Item>(gFormatKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1413
                                                      theFactory->createString(lFormat));
1414
    lJSONObject.push_back(lElemt);
1415
53 by Luis Rodriguez Gonzalez
All comments fixed
1416
    lElemt = std::make_pair<zorba::Item, zorba::Item>(gCompressionKey,
51 by Luis Rodriguez Gonzalez
Changes to make this module JSONiq friendly done.
1417
                                                      theFactory->createString(lCompression));
1418
    lJSONObject.push_back(lElemt);
1419
1420
    aRes = theFactory->createJSONObject(lJSONObject);
14.1.2 by Matthias Brantner
added the archive:options function to return algorithm and format options of an archive
1421
1422
    return true;
1423
  }
1424
5 by Juan Zacarias
Changed name to archive module
1425
/*******************************************************************************************
1426
 *******************************************************************************************/
28 by Juan Zacarias
Implemented the add in the archive update function
1427
  bool
1428
  UpdateFunction::UpdateItemSequence::UpdateIterator::next(
1429
    zorba::Item& aRes)
1430
  {
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1431
    struct archive_entry *lEntry = lookForHeader(false, &theOptions);
30 by Juan Zacarias
Added Delete Function
1432
    
1433
    //NULL is EOF
1434
    if (!lEntry)
1435
      return false;
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1436
28 by Juan Zacarias
Implemented the add in the archive update function
1437
    //form an ArchiveEntry with the entry
30.1.1 by Matthias Brantner
- fixed a memory leak in the update and delete functions
1438
    theEntry.setValues(lEntry);
42.1.6 by luisrod
- Added ability to create directories
1439
1440
    if(archive_entry_filetype(lEntry) == AE_IFREG){
1441
      //read entry content
1442
      std::vector<unsigned char> lResult;
1443
1444
      if (archive_entry_size_is_set(lEntry))
1445
      {
1446
        long long lSize = archive_entry_size(lEntry);
1447
        lResult.reserve(lSize);
1448
      }
1449
1450
      std::vector<unsigned char> lBuf;
1451
      lBuf.resize(ZORBA_ARCHIVE_MAX_READ_BUF);
1452
1453
      //read entry into string
1454
      while (true)
1455
      {
1456
        int s = archive_read_data(
1457
          theArchive, &lBuf[0], ZORBA_ARCHIVE_MAX_READ_BUF);
28 by Juan Zacarias
Implemented the add in the archive update function
1458
     
42.1.6 by luisrod
- Added ability to create directories
1459
        if (s == 0) break;
1460
1461
        lResult.insert(lResult.end(), lBuf.begin(), lBuf.begin() + s);
1462
      }
1463
49.1.1 by Paul J. Lucas
Fixes.
1464
      aRes = theFactory->createBase64Binary(reinterpret_cast<char const*>(&lResult[0]), lResult.size(), false);
28 by Juan Zacarias
Implemented the add in the archive update function
1465
    }
1466
1467
    return true;
1468
  }
1469
5 by Juan Zacarias
Changed name to archive module
1470
  zorba::ItemSequence_t
1471
    UpdateFunction::evaluate(
1472
      const Arguments_t& aArgs,
1473
      const zorba::StaticContext* aSctx,
1474
      const zorba::DynamicContext* aDctx) const 
1475
  {
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1476
    //Base64 Binary of the Archive
28 by Juan Zacarias
Implemented the add in the archive update function
1477
    Item lArchive = getOneItem(aArgs, 0);
1478
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1479
    //Initialize an Update Iterator with the Archive recived from the function
30 by Juan Zacarias
Added Delete Function
1480
    std::auto_ptr<UpdateItemSequence> lSeq(
1481
    new UpdateItemSequence(lArchive, false));
1482
28 by Juan Zacarias
Implemented the add in the archive update function
1483
    std::vector<ArchiveEntry> lEntries;
1484
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1485
    //prepare list of entries to be updated into the Archive
28 by Juan Zacarias
Implemented the add in the archive update function
1486
    {
1487
      Iterator_t lEntriesIter = aArgs[1]->getIterator();
1488
1489
      zorba::Item lEntry;
1490
      lEntriesIter->open();
30 by Juan Zacarias
Added Delete Function
1491
      ExtractFunction::ExtractItemSequence::EntryNameSet& lNameSet 
1492
          = lSeq->getNameSet();
28 by Juan Zacarias
Implemented the add in the archive update function
1493
      while (lEntriesIter->next(lEntry))
1494
      {
1495
        lEntries.resize(lEntries.size() + 1);
1496
        lEntries.back().setValues(lEntry);
30 by Juan Zacarias
Added Delete Function
1497
        lNameSet.insert(lEntries.back().getEntryPath().str());
28 by Juan Zacarias
Implemented the add in the archive update function
1498
      }
1499
      lEntriesIter->close();
30 by Juan Zacarias
Added Delete Function
1500
    } 
28 by Juan Zacarias
Implemented the add in the archive update function
1501
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1502
    //get the iterator of Files to include in the archive
28 by Juan Zacarias
Implemented the add in the archive update function
1503
    zorba::Iterator_t lFileIter = aArgs[2]->getIterator();
1504
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1505
    //Prepare new archive, for compressing the Files form the original 
1506
    //updated with the new Files specified
28 by Juan Zacarias
Implemented the add in the archive update function
1507
    ArchiveCompressor lResArchive;
30 by Juan Zacarias
Added Delete Function
1508
    ArchiveOptions lOptions;
28 by Juan Zacarias
Implemented the add in the archive update function
1509
1510
    Item lItem;
1511
    Iterator_t lSeqIter = lSeq->getIterator();
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1512
    
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1513
    //read first header and file of the archive so we can get the options before creating 
1514
    //the new archive.
28 by Juan Zacarias
Implemented the add in the archive update function
1515
    lSeqIter->open();
45.1.1 by Luis Rodriguez Gonzalez
-Replaced open functions with old ones to make it work with Macports
1516
    lSeqIter->next(lItem);
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1517
    //set the options of the archive
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1518
    lOptions = lSeq->getOptions();
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1519
    //create new archive with the options read
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1520
    lResArchive.open(lOptions);
45.1.1 by Luis Rodriguez Gonzalez
-Replaced open functions with old ones to make it work with Macports
1521
    if (!lItem.isNull())
28 by Juan Zacarias
Implemented the add in the archive update function
1522
    {
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1523
      do 
1524
      {
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1525
        //add and compress the files of the old archive into the new archive.
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1526
        lResArchive.compress(lSeq->getEntry(), lItem);
1527
      } while (lSeqIter->next(lItem));
28 by Juan Zacarias
Implemented the add in the archive update function
1528
    }
1529
    lSeqIter->close();
1530
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1531
    //add and compress the new file sspecified as a parameter for the function.
28 by Juan Zacarias
Implemented the add in the archive update function
1532
    lResArchive.compress(lEntries, lFileIter);
1533
    lResArchive.close();
1534
1535
    Item lRes = theModule->getItemFactory()->
1536
      createStreamableBase64Binary(
1537
      *lResArchive.getResultStream(),
1538
      &(ArchiveFunction::ArchiveCompressor::releaseStream),
1539
      true, // seekable
1540
      false // no encoded
1541
      );
1542
    return ItemSequence_t(new SingletonItemSequence(lRes));
7 by Matthias Brantner
fixed two build problems:
1543
  }
1544
5 by Juan Zacarias
Changed name to archive module
1545
/*******************************************************************************************
7 by Matthias Brantner
fixed two build problems:
1546
 *******************************************************************************************/
5 by Juan Zacarias
Changed name to archive module
1547
  zorba::ItemSequence_t
1548
    DeleteFunction::evaluate(
1549
      const Arguments_t& aArgs,
1550
      const zorba::StaticContext* aSctx,
1551
      const zorba::DynamicContext* aDctx) const 
1552
  {
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1553
    //Base64 Binary of the Archive
27.1.1 by luisrod
- a:delete() added
1554
    Item lArchive = getOneItem(aArgs, 0);
1555
30 by Juan Zacarias
Added Delete Function
1556
    std::auto_ptr<DeleteItemSequence> lSeq(
1557
      new DeleteItemSequence(lArchive));
27.1.1 by luisrod
- a:delete() added
1558
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1559
    //set list of files to delete from the archive.
27.1.1 by luisrod
- a:delete() added
1560
    zorba::Item lItem;
1561
    Iterator_t lIter = aArgs[1]->getIterator();
1562
    lIter->open();
30 by Juan Zacarias
Added Delete Function
1563
    ExtractFunction::ExtractItemSequence::EntryNameSet& lNameSet =
1564
      lSeq->getNameSet();
1565
    while (lIter->next(lItem))
1566
    {
1567
      lNameSet.insert(lItem.getStringValue().str());
1568
    }
1569
    lIter->close();
1570
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1571
    //prepare new archive
30 by Juan Zacarias
Added Delete Function
1572
    ArchiveCompressor lResArchive;
27.1.1 by luisrod
- a:delete() added
1573
    ArchiveOptions lOptions;
30 by Juan Zacarias
Added Delete Function
1574
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1575
    Item lContent;
30 by Juan Zacarias
Added Delete Function
1576
    Iterator_t lSeqIter = lSeq->getIterator();
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1577
    
1578
    //read first header and file of the archive so we can get the options before creating 
1579
    //the new archive.
30 by Juan Zacarias
Added Delete Function
1580
    lSeqIter->open();
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1581
    lSeqIter->next(lContent);
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1582
    //set the options of the archive
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1583
    lOptions = lSeq->getOptions();
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1584
    //create new archive with the options read
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1585
    lResArchive.open(lOptions);
1586
    if (!lContent.isNull())
30 by Juan Zacarias
Added Delete Function
1587
    {
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1588
      do 
1589
      {
36.1.1 by Juan Zacarias
Updated Delete and Update function's in line documentation
1590
        //add and compress the files of the old archive into the new archive.
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1591
        lResArchive.compress(lSeq->getEntry(), lContent);
1592
      } while (lSeqIter->next(lContent));
30 by Juan Zacarias
Added Delete Function
1593
    }
1594
    lSeqIter->close();
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1595
    
30 by Juan Zacarias
Added Delete Function
1596
    lResArchive.close();
27.1.1 by luisrod
- a:delete() added
1597
1598
    zorba::Item lRes = theModule->getItemFactory()->
1599
      createStreamableBase64Binary(
30 by Juan Zacarias
Added Delete Function
1600
        *lResArchive.getResultStream(),
27.1.1 by luisrod
- a:delete() added
1601
        &(ArchiveFunction::ArchiveCompressor::releaseStream),
1602
        true, // seekable
1603
        false // not encoded
1604
        );
1605
    return ItemSequence_t(new SingletonItemSequence(lRes));
1606
  }
1607
1608
  bool
1609
  DeleteFunction::DeleteItemSequence::DeleteIterator::next(
1610
      zorba::Item& aRes)
1611
  {
30.1.3 by Juan Zacarias
Added General Options to Delete and Update Function
1612
    struct archive_entry *lEntry = lookForHeader(false, &theOptions);
30 by Juan Zacarias
Added Delete Function
1613
    
1614
    //NULL is EOF
1615
    if (!lEntry)
1616
      return false;
1617
    
1618
    //form an ArchiveEntry with the entry
30.1.1 by Matthias Brantner
- fixed a memory leak in the update and delete functions
1619
    theEntry.setValues(lEntry);
42.1.6 by luisrod
- Added ability to create directories
1620
1621
    if(archive_entry_filetype(lEntry) == AE_IFREG){
30 by Juan Zacarias
Added Delete Function
1622
    
42.1.6 by luisrod
- Added ability to create directories
1623
      //read entry content
1624
      std::vector<unsigned char> lResult;
1625
1626
      if (archive_entry_size_is_set(lEntry))
1627
      {
1628
        long long lSize = archive_entry_size(lEntry);
1629
        lResult.reserve(lSize);
1630
      }
1631
1632
      std::vector<unsigned char> lBuf;
1633
      lBuf.resize(ZORBA_ARCHIVE_MAX_READ_BUF);
1634
1635
      //read entry into string
1636
      while (true)
1637
      {
1638
        int s = archive_read_data(
1639
          theArchive, &lBuf[0], ZORBA_ARCHIVE_MAX_READ_BUF);
30 by Juan Zacarias
Added Delete Function
1640
     
42.1.6 by luisrod
- Added ability to create directories
1641
        if (s == 0) break;
1642
1643
        lResult.insert(lResult.end(), lBuf.begin(), lBuf.begin() + s);
1644
      }
1645
49.1.1 by Paul J. Lucas
Fixes.
1646
      aRes = theFactory->createBase64Binary(reinterpret_cast<char const*>(&lResult[0]), lResult.size(), false);
27.1.1 by luisrod
- a:delete() added
1647
    }
42.1.6 by luisrod
- Added ability to create directories
1648
    // else? if the entry represents a directory what are we
1649
    // going to return??
53 by Luis Rodriguez Gonzalez
All comments fixed
1650
    // answer: nothing, the directory will have no contents at all
27.1.1 by luisrod
- a:delete() added
1651
1652
    return true;
1653
  }
1654
7 by Matthias Brantner
fixed two build problems:
1655
} /* namespace zorba */ } /* namespace archive*/
5 by Juan Zacarias
Changed name to archive module
1656
17 by Matthias Brantner
first very basic version of create#2 and #3
1657
std::ostream& std::operator<<(
1658
  std::ostream& out,
1659
  const zorba::archive::ArchiveFunction::ArchiveEntry& e)
1660
{
1661
  out << "name " << e.getEntryPath() << "; encoding " << e.getEncoding()
1662
    << "; last-modified " << e.getLastModified();
1663
  return out;
1664
}
1665
1666
5 by Juan Zacarias
Changed name to archive module
1667
#ifdef WIN32
1668
#  define DLL_EXPORT __declspec(dllexport)
1669
#else
1670
#  define DLL_EXPORT __attribute__ ((visibility("default")))
1671
#endif
1672
1673
extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
1674
  return new zorba::archive::ArchiveModule();
7 by Matthias Brantner
fixed two build problems:
1675
}