← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/feature-fetch_binary into lp:zorba

 

Matthias Brantner has proposed merging lp:~zorba-coders/zorba/feature-fetch_binary into lp:zorba.

Requested reviews:
  Matthias Brantner (matthias-brantner)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-fetch_binary/+merge/105155

- fetch:content-binary
- fetch:content#3 (with encoding parameter)
- StreamResource::isStreamSeekable to make sure the streamable strings returned by fetch are seekable.
-- 
https://code.launchpad.net/~zorba-coders/zorba/feature-fetch_binary/+merge/105155
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2012-05-09 00:44:36 +0000
+++ ChangeLog	2012-05-09 00:52:21 +0000
@@ -18,6 +18,7 @@
     - fn:has-children#0
     - fn:nilled#0
     - fn:path
+  * Added base64:decode#2 function which also does transcoding
   * Extended API for Python, Java, PHP and Ruby.
   * Add jvm classpath to zorbacmd and to Zorba API. Tracked by #931816
   * Added full-text module.
@@ -53,6 +54,7 @@
   * Fixed bug #912586, #912593 and #912722 (assertion failures with lax validation)
   * Fixed bug #921458 (file:read-text-lines() blocking)
   * Fixed bug #981405 (do not hoist expr containing try-catch variables out of the associated try-catch expression)
+  * Fixed bug #996084 (crash in Streamable*Item with file module)
   * Fixed bug #947627 (throw XQST0099 if more than one declarations of context item type in same module)
   * Fixed bug #980526 (no-copy rule bug due to global var being set in "distant" udf)
   * Fixed bug #949910 (has-children may be invoked on all nodes). Internally, zorba::store::Item::getChildren() now returns NULL on node classes without offspring (instead of raising an error).

=== modified file 'include/zorba/uri_resolvers.h'
--- include/zorba/uri_resolvers.h	2012-05-03 12:31:51 +0000
+++ include/zorba/uri_resolvers.h	2012-05-09 00:52:21 +0000
@@ -84,9 +84,11 @@
    * @param aStreamReleaser A function pointer which is invoked once
    *        the StreamResource is destroyed. Normally this function will delete
    *        the std::istream object passed to it.
+   * @param aIsStreamSeekable Determines whether the given stream is seekable.
    */
   static StreamResource* create(std::istream* aStream,
-                                StreamReleaser aStreamReleaser);
+                                StreamReleaser aStreamReleaser,
+                                bool aIsStreamSeekable = false);
   
   /**
    * @brief Retrieve the istream associated with this Resource.
@@ -99,6 +101,8 @@
   virtual StreamReleaser getStreamReleaser() = 0;
 
   virtual ~StreamResource() = 0;
+
+  virtual bool isStreamSeekable() const = 0;
 };
 
 /**

=== modified file 'modules/com/zorba-xquery/www/modules/converters/base64.xq'
--- modules/com/zorba-xquery/www/modules/converters/base64.xq	2012-05-03 12:31:51 +0000
+++ modules/com/zorba-xquery/www/modules/converters/base64.xq	2012-05-09 00:52:21 +0000
@@ -25,6 +25,8 @@
  :)
 module namespace base64 = "http://www.zorba-xquery.com/modules/converters/base64";;
 
+declare namespace zerr = "http://www.zorba-xquery.com/errors";;
+
 declare namespace ver = "http://www.zorba-xquery.com/options/versioning";;
 declare option ver:module-version "2.0";
 
@@ -32,7 +34,7 @@
  : Decode a xs:base64Binary.
  :
  : The function assumes that the content after decoding is valid
- : UTF-8. 
+ : UTF-8.
  :
  : @param $base64 The xs:base64Binary item to decode
  : @return the base64 decoded value as string
@@ -41,6 +43,24 @@
 as xs:string external;
 
 (:~
+ : Decode a xs:base64Binary.
+ :
+ : The function assumes that the content after decoding has
+ : the given encoding.
+ :
+ : @param $base64 The xs:base64Binary item to decode
+ : @param $encoding The encoding of the string after base64 decoding it.
+ :
+ : @return the base64 decoded value as string
+ :
+ : @error zerr:ZXQP0006 if the given encoding is invalid or not supported.
+ :)
+declare function base64:decode(
+  $base64 as xs:base64Binary,
+  $encoding as xs:string)
+as xs:string external;
+
+(:~
  : Encode a xs:string as xs:base64Binary.
  :
  : @param $string The item whose string-value should be encoded

=== modified file 'modules/com/zorba-xquery/www/modules/fetch.xq'
--- modules/com/zorba-xquery/www/modules/fetch.xq	2012-05-03 12:31:51 +0000
+++ modules/com/zorba-xquery/www/modules/fetch.xq	2012-05-09 00:52:21 +0000
@@ -96,5 +96,28 @@
  : @see <a href="../../html/uriresolvers.html">URI Resolvers</a>.
  : @see <a href="../../html/options_and_annotations.html">Documentation of Zorba's annotations</a>.
  :)
-
-declare %an:streamable function fetch:content($uri as xs:string, $entityKind as xs:string) as xs:string external;
+declare %an:streamable function fetch:content($uri as xs:string, $entityKind as xs:string)
+as xs:string
+{
+  fetch:content($uri, $entityKind, "UTF-8")
+};
+
+(:~
+ :)
+declare %an:streamable function fetch:content(
+  $uri as xs:string,
+  $entityKind as xs:string,
+  $encoding as xs:string)
+as xs:string external;
+
+(:~
+ :)
+declare %an:streamable function fetch:content-binary($uri as xs:string) as xs:base64Binary
+{
+  fetch:content-binary($uri, "SOME_CONTENT")
+};
+
+(:~
+ :)
+declare %an:streamable function fetch:content-binary($uri as xs:string, $entityKind as xs:string)
+as xs:base64Binary external;

=== modified file 'src/api/uri_resolver_wrappers.cpp'
--- src/api/uri_resolver_wrappers.cpp	2012-05-03 12:31:51 +0000
+++ src/api/uri_resolver_wrappers.cpp	2012-05-09 00:52:21 +0000
@@ -146,7 +146,9 @@
         // StreamResource, by passing the StreamReleaser to it and setting the
         // user's StreamResource's StreamReleaser to nullptr.
         lRetval = new internal::StreamResource(lUserStream->getStream(),
-                                           lUserStream->getStreamReleaser());
+                                           lUserStream->getStreamReleaser(),
+                                           "",
+                                           lUserStream->isStreamSeekable());
         lUserStream->setStreamReleaser(nullptr);
       }
 #ifndef ZORBA_NO_FULL_TEXT

=== modified file 'src/api/uriresolverimpl.cpp'
--- src/api/uriresolverimpl.cpp	2012-05-03 12:31:51 +0000
+++ src/api/uriresolverimpl.cpp	2012-05-09 00:52:21 +0000
@@ -43,15 +43,18 @@
   }
 
   StreamResource* StreamResource::create(std::istream* aStream,
-                                         StreamReleaser aStreamReleaser)
+                                         StreamReleaser aStreamReleaser,
+                                         bool aIsStreamSeekable)
   {
-    return new StreamResourceImpl(aStream, aStreamReleaser);
+    return new StreamResourceImpl(aStream, aStreamReleaser, aIsStreamSeekable);
   }
 
   StreamResourceImpl::StreamResourceImpl(std::istream* aStream,
-                                         StreamReleaser aStreamReleaser)
+                                         StreamReleaser aStreamReleaser,
+                                         bool aIsStreamSeekable)
     : theStream(aStream),
-      theStreamReleaser(aStreamReleaser)
+      theStreamReleaser(aStreamReleaser),
+      theIsStreamSeekable(aIsStreamSeekable)
   {
   }
 

=== modified file 'src/api/uriresolverimpl.h'
--- src/api/uriresolverimpl.h	2012-05-03 12:31:51 +0000
+++ src/api/uriresolverimpl.h	2012-05-09 00:52:21 +0000
@@ -39,14 +39,21 @@
 
   virtual void destroy() const;
 
+  virtual bool isStreamSeekable() const { return theIsStreamSeekable; }
+
 private:
 
-  StreamResourceImpl(std::istream* aStream, StreamReleaser aStreamReleaser);
+  StreamResourceImpl(
+      std::istream* aStream,
+      StreamReleaser aStreamReleaser,
+      bool aIsStreamSeekable);
 
   friend StreamResource* StreamResource::create(std::istream *aStream,
-                                                StreamReleaser aStreamReleaser);
+                                                StreamReleaser aStreamReleaser,
+                                                bool aIsStreamSeekable);
   std::istream* theStream;
   StreamReleaser theStreamReleaser;
+  bool theIsStreamSeekable;
 
 };
 

=== modified file 'src/context/default_url_resolvers.cpp'
--- src/context/default_url_resolvers.cpp	2012-05-03 12:31:51 +0000
+++ src/context/default_url_resolvers.cpp	2012-05-09 00:52:21 +0000
@@ -107,7 +107,8 @@
   zstring lPath = fs::get_normalized_path(aUrl);
   if (fs::get_type(lPath) == fs::file) {
     std::ifstream* lStream = new std::ifstream(lPath.c_str());
-    return new StreamResource(lStream, &fileStreamReleaser);
+    return new StreamResource(
+        lStream, &fileStreamReleaser, "", true /* seekable */);
   }
   return NULL;
 }

=== modified file 'src/context/uri_resolver.cpp'
--- src/context/uri_resolver.cpp	2012-05-03 12:31:51 +0000
+++ src/context/uri_resolver.cpp	2012-05-09 00:52:21 +0000
@@ -46,11 +46,13 @@
 
   StreamResource::StreamResource
   (std::istream* aStream, StreamReleaser aStreamReleaser,
-   zstring aStreamUrl /* = "" */)
+   zstring aStreamUrl /* = "" */,
+   bool aIsStreamSeekable)
     : Resource(),
       theStream(aStream),
       theStreamReleaser(aStreamReleaser),
-      theStreamUrl(aStreamUrl)
+      theStreamUrl(aStreamUrl),
+      theIsStreamSeekable(aIsStreamSeekable)
   {}
   
   StreamResource::~StreamResource()

=== modified file 'src/context/uri_resolver.h'
--- src/context/uri_resolver.h	2012-05-03 12:31:51 +0000
+++ src/context/uri_resolver.h	2012-05-09 00:52:21 +0000
@@ -97,10 +97,13 @@
    * are certain unusual circumstances where a URLResolver may wish to
    * return a stream over some other URL than the one passed to it. In
    * that case, the URLResolver may pass the true URL here.
+   * @param aIsStreamSeekable determines whether the stream passed as first
+   * argument is seekable.
    */
   StreamResource(std::istream* aStream,
                  StreamReleaser aStreamReleaser,
-                 zstring aStreamUrl = "");
+                 zstring aStreamUrl = "",
+                 bool aIsStreamSeekable = false);
   
   virtual ~StreamResource();
 
@@ -127,11 +130,18 @@
    */
   zstring getStreamUrl();
 
+  /**
+   * @brief Returns true if the stream returned by getStream is seekable,
+   * false otherwise.
+   */
+  bool isStreamSeekable() const { return theIsStreamSeekable; }
+
 private:
 
   std::istream* theStream;
   StreamReleaser theStreamReleaser;
   zstring theStreamUrl;
+  bool theIsStreamSeekable;
 };
 
 /**

=== modified file 'src/functions/pregenerated/func_base64.cpp'
--- src/functions/pregenerated/func_base64.cpp	2012-05-03 12:31:51 +0000
+++ src/functions/pregenerated/func_base64.cpp	2012-05-09 00:52:21 +0000
@@ -68,6 +68,19 @@
   {
     
 
+    DECL_WITH_KIND(sctx, fn_zorba_base64_decode,
+        (createQName("http://www.zorba-xquery.com/modules/converters/base64","","decode";), 
+        GENV_TYPESYSTEM.BASE64BINARY_TYPE_ONE, 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE, 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE),
+        FunctionConsts::FN_ZORBA_BASE64_DECODE_2);
+
+  }
+
+
+  {
+    
+
     DECL_WITH_KIND(sctx, fn_zorba_base64_encode,
         (createQName("http://www.zorba-xquery.com/modules/converters/base64","","encode";), 
         GENV_TYPESYSTEM.STRING_TYPE_ONE, 

=== modified file 'src/functions/pregenerated/func_fetch.cpp'
--- src/functions/pregenerated/func_fetch.cpp	2012-05-03 12:31:51 +0000
+++ src/functions/pregenerated/func_fetch.cpp	2012-05-09 00:52:21 +0000
@@ -41,6 +41,16 @@
   return new FetchContentIterator(sctx, loc, argv);
 }
 
+PlanIter_t fn_zorba_fetch_content_binary::codegen(
+  CompilerCB*,
+  static_context* sctx,
+  const QueryLoc& loc,
+  std::vector<PlanIter_t>& argv,
+  expr& ann) const
+{
+  return new FetchContentBinaryIterator(sctx, loc, argv);
+}
+
 PlanIter_t fn_zorba_fetch_content_type::codegen(
   CompilerCB*,
   static_context* sctx,
@@ -60,8 +70,22 @@
         (createQName("http://www.zorba-xquery.com/modules/fetch","","content";), 
         GENV_TYPESYSTEM.STRING_TYPE_ONE, 
         GENV_TYPESYSTEM.STRING_TYPE_ONE, 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE, 
         GENV_TYPESYSTEM.STRING_TYPE_ONE),
-        FunctionConsts::FN_ZORBA_FETCH_CONTENT_2);
+        FunctionConsts::FN_ZORBA_FETCH_CONTENT_3);
+
+  }
+
+
+  {
+    
+
+    DECL_WITH_KIND(sctx, fn_zorba_fetch_content_binary,
+        (createQName("http://www.zorba-xquery.com/modules/fetch","","content-binary";), 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE, 
+        GENV_TYPESYSTEM.STRING_TYPE_ONE, 
+        GENV_TYPESYSTEM.BASE64BINARY_TYPE_ONE),
+        FunctionConsts::FN_ZORBA_FETCH_CONTENT_BINARY_2);
 
   }
 

=== modified file 'src/functions/pregenerated/func_fetch.h'
--- src/functions/pregenerated/func_fetch.h	2012-05-03 12:31:51 +0000
+++ src/functions/pregenerated/func_fetch.h	2012-05-09 00:52:21 +0000
@@ -55,6 +55,23 @@
 };
 
 
+//fn-zorba-fetch:content-binary
+class fn_zorba_fetch_content_binary : public function
+{
+public:
+  fn_zorba_fetch_content_binary(const signature& sig, FunctionConsts::FunctionKind kind)
+    : 
+    function(sig, kind)
+  {
+
+  }
+
+  bool accessesDynCtx() const { return true; }
+
+  CODEGEN_DECL();
+};
+
+
 //fn-zorba-fetch:content-type
 class fn_zorba_fetch_content_type : public function
 {

=== modified file 'src/functions/pregenerated/function_enum.h'
--- src/functions/pregenerated/function_enum.h	2012-05-03 12:31:51 +0000
+++ src/functions/pregenerated/function_enum.h	2012-05-09 00:52:21 +0000
@@ -36,6 +36,7 @@
   FN_RESOLVE_URI_1,
   FN_RESOLVE_URI_2,
   FN_ZORBA_BASE64_DECODE_1,
+  FN_ZORBA_BASE64_DECODE_2,
   FN_ZORBA_BASE64_ENCODE_1,
   OP_IS_SAME_NODE_2,
   OP_NODE_BEFORE_2,
@@ -136,7 +137,8 @@
   FN_TRACE_2,
   OP_ZORBA_READ_LINE_0,
   FN_ZORBA_UTIL_PRINT_1,
-  FN_ZORBA_FETCH_CONTENT_2,
+  FN_ZORBA_FETCH_CONTENT_3,
+  FN_ZORBA_FETCH_CONTENT_BINARY_2,
   FN_ZORBA_FETCH_CONTENT_TYPE_1,
   FN_PUT_2,
   FULL_TEXT_CURRENT_LANG_0,

=== modified file 'src/runtime/base64/base64_impl.cpp'
--- src/runtime/base64/base64_impl.cpp	2012-05-03 12:31:51 +0000
+++ src/runtime/base64/base64_impl.cpp	2012-05-09 00:52:21 +0000
@@ -15,6 +15,9 @@
  */
 #include "stdafx.h"
 
+#include <sstream>
+#include <zorba/transcode_stream.h>
+
 #include "system/globalenv.h"
 
 #include "diagnostics/xquery_diagnostics.h"
@@ -33,6 +36,7 @@
 {
   store::Item_t lItem;
   zstring lResultString;
+  zstring lEncoding("UTF-8");
   const char* lContent;
   size_t lSize;
   result = NULL;
@@ -42,21 +46,45 @@
 
   consumeNext(lItem, theChildren[0].getp(), planState);
 
+  if (theChildren.size() == 2)
+  {
+    store::Item_t lEncodingItem;
+    consumeNext(lEncodingItem, theChildren[1].getp(), planState);
+    lEncoding = lEncodingItem->getStringValue();
+
+    if (!transcode::is_supported(lEncoding.c_str()))
+    {
+      throw XQUERY_EXCEPTION(
+        zerr::ZXQP0006_UNKNOWN_ENCODING,
+        ERROR_PARAMS( lEncoding ),
+        ERROR_LOC( loc )
+      );
+    }
+  }
+
   if (lItem->isStreamable())
   {
     if (lItem->isEncoded())
     {
-      // decode and eventually transcode
       lResultString = Base64::decode(lItem->getStream());
     }
     else
     {
-      // streamable string eventually transcoding
-      GENV_ITEMFACTORY->createStreamableString(
-          result,
-          lItem->getStream(),
-          lItem->getStreamReleaser(),
-          lItem->isSeekable());
+      if (transcode::is_necessary(lEncoding.c_str()))
+      {
+        transcode::attach(lItem->getStream(), lEncoding.c_str());
+        GENV_ITEMFACTORY->createStreamableString(
+            result,
+            lItem->getStream(),
+            lItem->getStreamReleaser(),
+            lItem->isSeekable());
+      }
+      else
+      {
+        GENV_ITEMFACTORY->createSharedStreamableString(
+            result,
+            lItem);
+      }
     }
   }
   else
@@ -74,10 +102,37 @@
     {
       lResultString.insert(0, lContent, lSize);
     }
-  }
-  if (!result) // otherwise it's a streamable string already
-  {
-    GENV_ITEMFACTORY->createString(result, lResultString);
+
+    if (transcode::is_necessary(lEncoding.c_str()))
+    {
+      try
+      {
+        zstring lTranscodedString;
+        transcode::stream<std::istringstream> lTranscoder(
+            lEncoding.c_str(),
+            lResultString.c_str()
+          );
+        char buf[1024];
+        while (lTranscoder.good())
+        {
+          lTranscoder.read(buf, 1024);
+          lTranscodedString.append(buf, lTranscoder.gcount());
+        }
+        GENV_ITEMFACTORY->createString(result, lTranscodedString);
+      }
+      catch (ZorbaException& e)
+      {
+        throw XQUERY_EXCEPTION(
+          zerr::ZOSE0006_TRANSCODING_ERROR,
+          ERROR_PARAMS( e.what() ),
+          ERROR_LOC( loc )
+        );
+      }
+    }
+    else
+    {
+      GENV_ITEMFACTORY->createString(result, lResultString);
+    }
   }
   STACK_PUSH (true, state);
 

=== modified file 'src/runtime/fetch/fetch_impl.cpp'
--- src/runtime/fetch/fetch_impl.cpp	2012-05-03 12:31:51 +0000
+++ src/runtime/fetch/fetch_impl.cpp	2012-05-09 00:52:21 +0000
@@ -15,6 +15,8 @@
  */
 #include "stdafx.h"
 
+#include <zorba/transcode_stream.h>
+
 #include "diagnostics/assert.h"
 #include "diagnostics/xquery_diagnostics.h"
 
@@ -30,33 +32,17 @@
 
 /*******************************************************************************
 ********************************************************************************/
-void
-FetchContentIterator::destroyStream(std::istream& aStream)
-{
-  delete &aStream;
-}
-
-bool
-FetchContentIterator::nextImpl(
-    store::Item_t& result,
-    PlanState& aPlanState) const
-{
-  store::Item_t lUri;
-  store::Item_t lEntityKind;
+std::auto_ptr<internal::Resource>
+getFetchResource(
+    const store::Item_t& aUri,
+    const store::Item_t& aKind,
+    const static_context* aSctx,
+    const QueryLoc& aLoc)
+{
   internal::EntityData::Kind lKind;
-  zstring lKindStr;
-  zstring lErrorMessage;
-  std::auto_ptr<internal::Resource> lRes;
-  internal::StreamResource* lStreamRes;
-
-  PlanIteratorState* state;
-  DEFAULT_STACK_INIT(PlanIteratorState, state, aPlanState);
-
-  consumeNext(lUri, theChildren[0].getp(), aPlanState);
-  consumeNext(lEntityKind, theChildren[1].getp(), aPlanState);
+  zstring lKindStr = aKind->getStringValue();
 
   // Figure out the EntityKind (any better way to do this?)
-  lKindStr = lEntityKind->getStringValue();
   if ( ! lKindStr.compare("SOME_CONTENT")) {
     lKind = internal::EntityData::SOME_CONTENT;
   }
@@ -70,7 +56,7 @@
   else if ( ! lKindStr.compare("THESAURUS")) {
     lKind = internal::EntityData::THESAURUS;
   }
-  else if ( ! lKindStr.compare("STOP_WORDS")) {
+  else if ( ! lKindStr.compare("STOP_WORDS")){
     lKind = internal::EntityData::STOP_WORDS;
   }
 #endif /* ZORBA_NO_FULL_TEXT */
@@ -78,14 +64,15 @@
     throw XQUERY_EXCEPTION(
           zerr::ZXQP0026_INVALID_ENUM_VALUE,
           ERROR_PARAMS(lKindStr, "entityKind"),
-          ERROR_LOC(loc));
+          ERROR_LOC(aLoc));
   }
 
   try {
     // ask the uri mappers and resolvers to give
     // me a resource of specified kind
-    lRes = theSctx->resolve_uri(
-      lUri->getStringValue(),
+    zstring lErrorMessage;
+    return aSctx->resolve_uri(
+      aUri->getStringValue(),
       lKind,
       lErrorMessage);
 
@@ -93,9 +80,41 @@
     throw XQUERY_EXCEPTION(
       zerr::ZXQP0025_ITEM_CREATION_FAILED,
       ERROR_PARAMS( e.what() ),
-      ERROR_LOC( loc )
+      ERROR_LOC( aLoc )
     );
   }
+}
+
+/*******************************************************************************
+********************************************************************************/
+void
+FetchContentIterator::destroyStream(std::istream& aStream)
+{
+  delete &aStream;
+}
+
+bool
+FetchContentIterator::nextImpl(
+    store::Item_t& result,
+    PlanState& aPlanState) const
+{
+  store::Item_t lUri;
+  store::Item_t lEntityKind;
+  store::Item_t lEncoding;
+  zstring lEncodingStr("UTF-8");
+  std::auto_ptr<internal::Resource> lRes;
+  internal::StreamResource* lStreamRes;
+
+  PlanIteratorState* state;
+  DEFAULT_STACK_INIT(PlanIteratorState, state, aPlanState);
+
+  consumeNext(lUri, theChildren[0].getp(), aPlanState);
+  consumeNext(lEntityKind, theChildren[1].getp(), aPlanState);
+  consumeNext(lEncoding, theChildren[2].getp(), aPlanState);
+
+  lEncodingStr = lEncoding->getStringValue();
+
+  lRes = getFetchResource(lUri, lEntityKind, theSctx, loc);
 
   lStreamRes = dynamic_cast<internal::StreamResource*>(lRes.get());
   if ( !lStreamRes ) {
@@ -106,13 +125,80 @@
     );
   }
 
+  if (transcode::is_necessary(lEncodingStr.c_str()))
+  {
+    if (!transcode::is_supported(lEncodingStr.c_str()))
+    {
+      throw XQUERY_EXCEPTION(
+          zerr::ZXQP0006_UNKNOWN_ENCODING,
+          ERROR_PARAMS( lEncodingStr.c_str() ),
+          ERROR_LOC( loc )
+        );
+    }
+    transcode::attach(*lStreamRes->getStream(), lEncodingStr.c_str());
+  }
+
   // return the resource in a streamable string. This transfers memory
   // ownership of the istream (via its StreamReleaser) to the StreamableString
   // object, so we then remove the StreamReleaser from the StreamResource.
   GENV_ITEMFACTORY->createStreamableString(
         result,
         *lStreamRes->getStream(),
-        lStreamRes->getStreamReleaser()
+        lStreamRes->getStreamReleaser(),
+        lStreamRes->isStreamSeekable()
+  );
+  lStreamRes->setStreamReleaser(nullptr);
+
+  STACK_PUSH(result != NULL, state);
+
+  STACK_END(state);
+}
+
+
+/*******************************************************************************
+********************************************************************************/
+void
+FetchContentBinaryIterator::destroyStream(std::istream& aStream)
+{
+  delete &aStream;
+}
+
+bool
+FetchContentBinaryIterator::nextImpl(
+    store::Item_t& result,
+    PlanState& aPlanState) const
+{
+  store::Item_t lUri;
+  store::Item_t lEntityKind;
+  std::auto_ptr<internal::Resource> lRes;
+  internal::StreamResource* lStreamRes;
+
+  PlanIteratorState* state;
+  DEFAULT_STACK_INIT(PlanIteratorState, state, aPlanState);
+
+  consumeNext(lUri, theChildren[0].getp(), aPlanState);
+  consumeNext(lEntityKind, theChildren[1].getp(), aPlanState);
+
+  lRes = getFetchResource(lUri, lEntityKind, theSctx, loc);
+
+  lStreamRes = dynamic_cast<internal::StreamResource*>(lRes.get());
+  if ( !lStreamRes ) {
+    throw XQUERY_EXCEPTION(
+      zerr::ZXQP0025_ITEM_CREATION_FAILED,
+      ERROR_PARAMS( "Resource not available." ),
+      ERROR_LOC( loc )
+    );
+  }
+
+  // return the resource in a streamable base64. This transfers memory
+  // ownership of the istream (via its StreamReleaser) to the StreamableBase64BinaryItem
+  // object, so we then remove the StreamReleaser from the StreamResource.
+  GENV_ITEMFACTORY->createStreamableBase64Binary(
+        result,
+        *lStreamRes->getStream(),
+        lStreamRes->getStreamReleaser(),
+        lStreamRes->isStreamSeekable(),
+        false
   );
   lStreamRes->setStreamReleaser(nullptr);
 

=== modified file 'src/runtime/fetch/pregenerated/fetch.cpp'
--- src/runtime/fetch/pregenerated/fetch.cpp	2012-05-03 12:31:51 +0000
+++ src/runtime/fetch/pregenerated/fetch.cpp	2012-05-09 00:52:21 +0000
@@ -54,6 +54,28 @@
 // </FetchContentIterator>
 
 
+// <FetchContentBinaryIterator>
+FetchContentBinaryIterator::class_factory<FetchContentBinaryIterator>
+FetchContentBinaryIterator::g_class_factory;
+
+
+void FetchContentBinaryIterator::accept(PlanIterVisitor& v) const {
+  v.beginVisit(*this);
+
+  std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
+  std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
+  for ( ; lIter != lEnd; ++lIter ){
+    (*lIter)->accept(v);
+  }
+
+  v.endVisit(*this);
+}
+
+FetchContentBinaryIterator::~FetchContentBinaryIterator() {}
+
+// </FetchContentBinaryIterator>
+
+
 // <FetchContentTypeIterator>
 FetchContentTypeIterator::class_factory<FetchContentTypeIterator>
 FetchContentTypeIterator::g_class_factory;

=== modified file 'src/runtime/fetch/pregenerated/fetch.h'
--- src/runtime/fetch/pregenerated/fetch.h	2012-05-03 12:31:51 +0000
+++ src/runtime/fetch/pregenerated/fetch.h	2012-05-09 00:52:21 +0000
@@ -73,6 +73,42 @@
  * 
  * Author: Matthias Brantner
  */
+class FetchContentBinaryIterator : public NaryBaseIterator<FetchContentBinaryIterator, PlanIteratorState>
+{ 
+public:
+  SERIALIZABLE_CLASS(FetchContentBinaryIterator);
+
+  SERIALIZABLE_CLASS_CONSTRUCTOR2T(FetchContentBinaryIterator,
+    NaryBaseIterator<FetchContentBinaryIterator, PlanIteratorState>);
+
+  void serialize( ::zorba::serialization::Archiver& ar)
+  {
+    serialize_baseclass(ar,
+    (NaryBaseIterator<FetchContentBinaryIterator, PlanIteratorState>*)this);
+  }
+
+  FetchContentBinaryIterator(
+    static_context* sctx,
+    const QueryLoc& loc,
+    std::vector<PlanIter_t>& children)
+    : 
+    NaryBaseIterator<FetchContentBinaryIterator, PlanIteratorState>(sctx, loc, children)
+  {}
+
+  virtual ~FetchContentBinaryIterator();
+
+public:
+  static void destroyStream(std::istream& aStream);
+  void accept(PlanIterVisitor& v) const;
+
+  bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
+};
+
+
+/**
+ * 
+ * Author: Matthias Brantner
+ */
 class FetchContentTypeIterator : public NaryBaseIterator<FetchContentTypeIterator, PlanIteratorState>
 { 
 public:

=== modified file 'src/runtime/spec/base64/base64.xml'
--- src/runtime/spec/base64/base64.xml	2012-05-03 12:31:51 +0000
+++ src/runtime/spec/base64/base64.xml	2012-05-09 00:52:21 +0000
@@ -25,8 +25,13 @@
       <zorba:param>xs:base64Binary</zorba:param>
       <zorba:output>xs:string</zorba:output>
     </zorba:signature>
+    <zorba:signature localname="decode" prefix="fn-zorba-base64">
+      <zorba:param>xs:base64Binary</zorba:param>
+      <zorba:param>xs:string</zorba:param> <!-- encoding -->
+      <zorba:output>xs:string</zorba:output>
+    </zorba:signature>
   </zorba:function>
-    
+
 </zorba:iterator>
 
 <!--

=== modified file 'src/runtime/spec/fetch/fetch.xml'
--- src/runtime/spec/fetch/fetch.xml	2012-05-03 12:31:51 +0000
+++ src/runtime/spec/fetch/fetch.xml	2012-05-09 00:52:21 +0000
@@ -16,7 +16,8 @@
   <zorba:function>
     <zorba:signature localname="content" prefix="fn-zorba-fetch">
       <zorba:param>xs:string</zorba:param>
-      <zorba:param>xs:string</zorba:param>
+      <zorba:param>xs:string</zorba:param> <!-- entityKind -->
+      <zorba:param>xs:string</zorba:param> <!-- encoding -->
       <zorba:output>xs:string</zorba:output>
     </zorba:signature>
 
@@ -25,8 +26,33 @@
     </zorba:methods>
   </zorba:function>
 
-  <zorba:method static="true" name="destroyStream"
-    return="void">
+  <zorba:method static="true" name="destroyStream" return="void">
+    <zorba:param type="std::istream&amp;" name="aStream"/>
+  </zorba:method>
+
+</zorba:iterator>
+
+<!--
+/*********************************************************************
+*********************************************************************/
+-->
+<zorba:iterator name="FetchContentBinaryIterator">
+
+  <zorba:description author="Matthias Brantner"></zorba:description>
+
+  <zorba:function>
+    <zorba:signature localname="content-binary" prefix="fn-zorba-fetch">
+      <zorba:param>xs:string</zorba:param>
+      <zorba:param>xs:string</zorba:param>
+      <zorba:output>xs:base64Binary</zorba:output>
+    </zorba:signature>
+
+    <zorba:methods>
+      <zorba:accessesDynCtx returnValue="true"/>
+    </zorba:methods>
+  </zorba:function>
+
+  <zorba:method static="true" name="destroyStream" return="void">
     <zorba:param type="std::istream&amp;" name="aStream"/>
   </zorba:method>
 

=== modified file 'src/runtime/visitors/pregenerated/planiter_visitor.h'
--- src/runtime/visitors/pregenerated/planiter_visitor.h	2012-05-03 12:31:51 +0000
+++ src/runtime/visitors/pregenerated/planiter_visitor.h	2012-05-09 00:52:21 +0000
@@ -189,6 +189,8 @@
 
     class FetchContentIterator;
 
+    class FetchContentBinaryIterator;
+
     class FetchContentTypeIterator;
 
     class FnPutIterator;
@@ -897,6 +899,9 @@
     virtual void beginVisit ( const FetchContentIterator& ) = 0;
     virtual void endVisit   ( const FetchContentIterator& ) = 0;
 
+    virtual void beginVisit ( const FetchContentBinaryIterator& ) = 0;
+    virtual void endVisit   ( const FetchContentBinaryIterator& ) = 0;
+
     virtual void beginVisit ( const FetchContentTypeIterator& ) = 0;
     virtual void endVisit   ( const FetchContentTypeIterator& ) = 0;
 

=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.cpp'
--- src/runtime/visitors/pregenerated/printer_visitor.cpp	2012-05-03 12:31:51 +0000
+++ src/runtime/visitors/pregenerated/printer_visitor.cpp	2012-05-09 00:52:21 +0000
@@ -1219,6 +1219,20 @@
 // </FetchContentIterator>
 
 
+// <FetchContentBinaryIterator>
+void PrinterVisitor::beginVisit ( const FetchContentBinaryIterator& a) {
+  thePrinter.startBeginVisit("FetchContentBinaryIterator", ++theId);
+  printCommons( &a, theId );
+  thePrinter.endBeginVisit( theId );
+}
+
+void PrinterVisitor::endVisit ( const FetchContentBinaryIterator& ) {
+  thePrinter.startEndVisit();
+  thePrinter.endEndVisit();
+}
+// </FetchContentBinaryIterator>
+
+
 // <FetchContentTypeIterator>
 void PrinterVisitor::beginVisit ( const FetchContentTypeIterator& a) {
   thePrinter.startBeginVisit("FetchContentTypeIterator", ++theId);

=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.h'
--- src/runtime/visitors/pregenerated/printer_visitor.h	2012-05-03 12:31:51 +0000
+++ src/runtime/visitors/pregenerated/printer_visitor.h	2012-05-09 00:52:21 +0000
@@ -286,6 +286,9 @@
     void beginVisit( const FetchContentIterator& );
     void endVisit  ( const FetchContentIterator& );
 
+    void beginVisit( const FetchContentBinaryIterator& );
+    void endVisit  ( const FetchContentBinaryIterator& );
+
     void beginVisit( const FetchContentTypeIterator& );
     void endVisit  ( const FetchContentTypeIterator& );
 

=== modified file 'src/store/api/item_factory.h'
--- src/store/api/item_factory.h	2012-05-03 12:31:51 +0000
+++ src/store/api/item_factory.h	2012-05-09 00:52:21 +0000
@@ -97,6 +97,19 @@
       bool seekable = false) = 0;
 
   /**
+   * Create a StreamableStringItem which re-uses the stream from another
+   * Streamable*Item. This will maintain a reference to the original
+   * item to ensure the stream is not cleaned up before we are done with it.
+   *
+   * It only makes sense to use this method if either (a) the dependent item's
+   * stream is seekable and hence re-usable, or (b) you are sure that the
+   * dependent item will not be utilized after this new item is created.
+   */
+  virtual bool createSharedStreamableString(
+      Item_t& result,
+      Item_t& streamble_dependent) = 0;
+
+  /**
    * Specification: [http://www.w3.org/TR/xmlschema-2/#normalizedString]
    * @param value string representation of the value
    */

=== modified file 'src/store/naive/atomic_items.cpp'
--- src/store/naive/atomic_items.cpp	2012-05-04 14:32:28 +0000
+++ src/store/naive/atomic_items.cpp	2012-05-09 00:52:21 +0000
@@ -1673,6 +1673,36 @@
 /*******************************************************************************
   class StreamableStringItem
 ********************************************************************************/
+StreamableStringItem::StreamableStringItem(
+    std::istream& aStream,
+    StreamReleaser streamReleaser,
+    bool seekable) :
+  theIstream(aStream),
+  theIsMaterialized(false),
+  theIsConsumed(false),
+  theIsSeekable(seekable),
+  theStreamReleaser(streamReleaser),
+  theStreamableDependent(nullptr)
+{
+}
+
+StreamableStringItem::StreamableStringItem(
+    store::Item_t& aStreamableDependent) :
+  theIstream(aStreamableDependent->getStream()),
+  theIsMaterialized(false),
+  theIsConsumed(false),
+  theIsSeekable(aStreamableDependent->isSeekable()),
+  theStreamReleaser(nullptr),
+  theStreamableDependent(aStreamableDependent)
+{
+  ZORBA_ASSERT(theStreamableDependent->isStreamable());
+
+  // We copied the dependent item's stream and seekable flag in the initializer
+  // above, but did NOT copy the StreamReleaser. The dependent item maintains
+  // memory ownership of the stream in this way.
+}
+
+
 void StreamableStringItem::appendStringValue(zstring& aBuf) const
 {
   if (!theIsMaterialized) 

=== modified file 'src/store/naive/atomic_items.h'
--- src/store/naive/atomic_items.h	2012-05-03 12:31:51 +0000
+++ src/store/naive/atomic_items.h	2012-05-09 00:52:21 +0000
@@ -875,6 +875,8 @@
 
   StreamReleaser theStreamReleaser;
 
+  store::Item_t theStreamableDependent;
+
 public:
   bool equals(
         store::Item const*,
@@ -922,15 +924,10 @@
   StreamableStringItem(
       std::istream& aStream,
       StreamReleaser streamReleaser,
-      bool seekable = false)
-    :
-    theIstream(aStream),
-    theIsMaterialized(false),
-    theIsConsumed(false),
-    theIsSeekable(seekable),
-    theStreamReleaser(streamReleaser)
-  {
-  }
+      bool seekable = false);
+
+  StreamableStringItem(
+      store::Item_t& aStreamableDependent);
 
   void materialize() const;
 };

=== modified file 'src/store/naive/simple_item_factory.cpp'
--- src/store/naive/simple_item_factory.cpp	2012-05-03 12:31:51 +0000
+++ src/store/naive/simple_item_factory.cpp	2012-05-09 00:52:21 +0000
@@ -157,6 +157,14 @@
   return true;
 }
 
+bool BasicItemFactory::createSharedStreamableString(
+    store::Item_t &result,
+    store::Item_t &streamable_dependent)
+{
+  result = new StreamableStringItem( streamable_dependent );
+  return true;
+}
+
 
 bool BasicItemFactory::createNormalizedString(store::Item_t& result, zstring& value)
 {

=== modified file 'src/store/naive/simple_item_factory.h'
--- src/store/naive/simple_item_factory.h	2012-05-03 12:31:51 +0000
+++ src/store/naive/simple_item_factory.h	2012-05-09 00:52:21 +0000
@@ -106,6 +106,10 @@
       StreamReleaser,
       bool seekable = false);
 
+  bool createSharedStreamableString(
+      store::Item_t& result,
+      store::Item_t& streamable_dependent);
+
   bool createBase64Binary(store::Item_t& result, xs_base64Binary value);
 
   bool createBase64Binary(

=== added file 'test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1.xml.res'
--- test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+äöü

=== added file 'test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1_file.xml.res'
--- test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1_file.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/base64/decode_iso-8859-1_file.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+äöü

=== added file 'test/rbkt/ExpQueryResults/zorba/base64/reuse-stream.xml.res'
--- test/rbkt/ExpQueryResults/zorba/base64/reuse-stream.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/base64/reuse-stream.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+<file><content>f0VMRgEBAQAAAAAAAAAAAAMAAwABAAAAIPxDADQAAAD0JTMHAAAAADQAIAAHACgAKAAlAAEAAAAAAAAAAAAAAAAAAAAv22gBL9toAQUAAAAAEAAAAQAAAJTbaAGU62gBlOtoAehnBwAwpgcABgAAAAAQAAACAAAAvKBuAbywbgG8sG4BGAEAABgBAAAGAAAABAAAAAQAAAAUAQAAFAEAABQBAAAkAAAAJAAAAAQAAAAEAAAAUOV0ZKyHJwGshycBrIcnAfyBCAD8gQgABAAAAAQAAABR5XRkAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAABAAAAFLldGSU22gBlOtoAZTraAFs5AUAbOQFAAQAAAABAAAABAAAABQAAAADAAAAR05VANMOFlHRDhyfmkw9H3+lYuAncwGhG0AAAAYDAAAAIAAAEgAAABBkRVIkEIgUIwhRukiBHLCOBAAEAgggoSCCg0CkED5YAAAGFAIgABkACJAAiQAwAFCQEwAQIABBAIIFYAIACAASAAZARACAABkTpAQB5EQIYEF0IBIAIgAhciYEoEICZGgAAQAABCAAkBACZAJAAQQUEhGAIIAAKBULIJYAAABRAKFV4AIWgQAEIYgAAIAAQECAMgBGiCIGiRAEkAABAMAIgEQAAAQAACgIJYAAAEAAAAGAAgtCpFwEAAZRQACAABAICAASiBBFgRhIAkEBMAApJchACQZDAIAAgABIAKQEgKEACGE05FgCAAAgACEAgEAAQoxkUAEAiBAGAAkCFiBoISRFFCBEBMV3gARBgBAosUJBQQAEEDIAUUCBAABAEAhgAEAAAAAAACApACIBBgHKkAWBQAAEAAAAAACDURggAkEEEIlEgIEADQZwAAATC5AQNYxCABABAAAAAAEAlQD0WGD3gAAAIEDKCCAQQMGNIAAQAAAACECCAADAbMAWABABaRAAUFQCgAAAgxJmDAEIAiIZCmIAIAIEgAESCSAjETEQIws2A8AIgAEAAAAAkGkAiEAKDEYEBRGJhFEAIACICAIBKMAGAAAHIAQBqIgAUAECgAAAAhoEER4BASMBBhEIIQGCAFbg8IiBYAgCAQgAgEBwCAAAIAEAQATGAj+QQaAIIQAIAAShAgg2AKQAAAQBkCoASAAAFAAgAYFqAQDCcoOEg0sAIhKAABQAAgpAAghAAIQgIBAkAAQBDA4gRAACAAIgAPBAUgBDARCAggB0GQBaEAg1Mk8CABEAAAQgBBgAECIAvEIhFCRAIBgAAEALyBEQAhACQoIKwAABkBiAVM4QAQlFgBAS4AASAIIkAZEkEgAsBMCABSCAKACAIBMAD4JSLEyAAGQBBqATAUECQUgACQGBGA==</content><md5>f027633a677f42caf1544f6913bc2dab</md5></file>
\ No newline at end of file

=== added file 'test/rbkt/ExpQueryResults/zorba/fetch/fetch_binary_1.xml.res'
--- test/rbkt/ExpQueryResults/zorba/fetch/fetch_binary_1.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/fetch/fetch_binary_1.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+eHF1ZXJ5IHZlcnNpb24gIjMuMCI7CgooOgogOiBDb3B5cmlnaHQgMjAwNi0yMDA5IFRoZSBGTFdPUiBGb3VuZGF0aW9uLgogOgogOiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIDogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogOiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKIDoKIDogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiA6CiA6IFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKIDogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIDogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiA6IFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKIDogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCjopCgooOn4KIDogVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIGZldGNoIHRoZSBjb250ZW50cyBvciB0aGUgdHlwZQogOiBvZiB0aGUgY29udGVudCBmb3IgYSByZXNvdXJjZSBpZGVudGlmaWVkIGJ5IGEgVVJJLgogOiBGb3IgZXhhbXBsZSwgaXQgZmV0Y2hlcyBjb250ZW50IGZvciBmaWxlIG9yIGh0dHAgcmVzb3VyY2VzIGlmIFpvcmJhCiA6IGFsbG93cyBmaWxlIG9yIGh0dHAgYWNjZXNzLCByZXNwZWN0aXZlbHkuCiA6CiA6IDxwPlRoZSBlcnJvcnMgcmFpc2VkIGJ5IGZ1bmN0aW9ucyBvZiB0aGlzIG1vZHVsZSBoYXZlIHRoZSBuYW1lc3BhY2UKIDogPHR0Pmh0dHA6Ly93d3cuem9yYmEteHF1ZXJ5LmNvbS9lcnJvcnM8L3R0PiAoYXNzb2NpYXRlZCB3aXRoIHByZWZpeCB6ZXJyKS48L3A+CiA6CiA6IEBzZWUgPGEgaHJlZj0id3d3LnpvcmJhLXhxdWVyeS5jb21fZXJyb3JzLmh0bWwiPmh0dHA6Ly93d3cuem9yYmEteHF1ZXJ5LmNvbS9lcnJvcnM8L2E+CiA6CiA6IEBhdXRob3IgTWF0dGhpYXMgQnJhbnRuZXIKIDoKIDogQHByb2plY3QgZXh0ZXJuYWwKIDopCm1vZHVsZSBuYW1lc3BhY2UgZmV0Y2ggPSAiaHR0cDovL3d3dy56b3JiYS14cXVlcnkuY29tL21vZHVsZXMvZmV0Y2giOwoKZGVjbGFyZSBuYW1lc3BhY2UgYW4gPSAiaHR0cDovL3d3dy56b3JiYS14cXVlcnkuY29tL2Fubm90YXRpb25zIjsKCmRlY2xhcmUgbmFtZXNwYWNlIHplcnIgPSAiaHR0cDovL3d3dy56b3JiYS14cXVlcnkuY29tL2Vycm9ycyI7CgpkZWNsYXJlIG5hbWVzcGFjZSB2ZXIgPSAiaHR0cDovL3d3dy56b3JiYS14cXVlcnkuY29tL29wdGlvbnMvdmVyc2lvbmluZyI7CmRlY2xhcmUgb3B0aW9uIHZlcjptb2R1bGUtdmVyc2lvbiAiMi4wIjsKCig6fgogOiA8cD5UcmllcyB0byBmZXRjaCB0aGUgcmVzb3VyY2UgcmVmZXJyZWQgdG8gYnkgdGhlIGdpdmVuIFVSSS48L3A+CiA6CiA6IDxwPkluIG9yZGVyIHRvIHJldHJpZXZlIHRoZSBjb250ZW50LCB0aGUgZnVuY3Rpb25zIHVzZXMgdGhlCiA6IFVSSSByZXNvbHV0aW9uIGFuZCBVUkwgcmVzb2x2ZXIgcHJvY2VzcyBhcyBkb2N1bWVudGVkIGF0CiA6IDxhIGhyZWY9Ii4uLy4uL2h0bWwvdXJpcmVzb2x2ZXJzLmh0bWwiPgogOiBVUkkgUmVzb2x2ZXJzPC9hPi4gVGhlcmVmb3JlLCBpdCBxdWVyaWVzIGFsbCBVUkkgbWFwcGVycwogOiBhbmQgcmVzb2x2ZXJzIHdpdGgga2luZCA8dHQ+RW50aXR5RGF0YTo6U09NRV9DT05URU5UPC90dD4uPC9wPgogOgogOiA8cD5UaGUgZnVuY3Rpb24gaXMgYW5ub3RhdGVkIHdpdGggdGhlIDx0dD5hbjpzdHJlYW1hYmxlPC90dD4KIDogYW5ub3RhdGlvbiwgdGhhdCBpcyBpdCByZXR1cm5zIGEgc3RyZWFtYWJsZSBzdHJpbmcuIEEgc3RyZWFtYWJsZQogOiBzdHJpbmcgY2FuIG9ubHkgYmUgY29uc3VtZWQgb25jZS4gUGxlYXNlIHNlZSBzZWN0aW9uICJTdHJlYW1hYmxlIFN0cmluZ3MiCiA6IGluIHRoZSA8YSBocmVmPSIuLi8uLi9odG1sL29wdGlvbnNfYW5kX2Fubm90YXRpb25zLmh0bWwiPgogOiBkb2N1bWVudGF0aW9uIG9mIFpvcmJhJ3MgYW5ub3RhdGlvbnM8L2E+LgogOiA8L3A+CiA6CiA6IEBwYXJhbSAkdXJpIHRoZSByZXNvdXJjZSB0byBmZXRjaC4KIDogQHJldHVybiB0aGUgcmVzb3VyY2UgcmVmZXJyZWQgdG8gYnkgdGhlIGdpdmVuIFVSSSBhcyBzdHJlYW1ibGUgc3RyaW5nLgogOgogOiBAZXJyb3IgemVycjpaWFFQMDAyNSBpZiB0aGUgVVJJIGNvdWxkIG5vdCBiZSByZXNvbHZlZAogOiAgIG9yIGRpZCBub3QgcmVzb2x2ZSB0byBhIDx0dD5TdHJlYW1SZXNvdXJjZTwvdHQ+LgogOgogOiBAc2VlIDxhIGhyZWY9Ii4uLy4uL2h0bWwvdXJpcmVzb2x2ZXJzLmh0bWwiPlVSSSBSZXNvbHZlcnM8L2E+LgogOiBAc2VlIDxhIGhyZWY9Ii4uLy4uL2h0bWwvb3B0aW9uc19hbmRfYW5ub3RhdGlvbnMuaHRtbCI+RG9jdW1lbnRhdGlvbiBvZiBab3JiYSdzIGFubm90YXRpb25zPC9hPi4KIDopCmRlY2xhcmUgJWFuOnN0cmVhbWFibGUgZnVuY3Rpb24gZmV0Y2g6Y29udGVudCgkdXJpIGFzIHhzOnN0cmluZykgYXMgeHM6c3RyaW5nCnsKICBmZXRjaDpjb250ZW50KCR1cmksICJTT01FX0NPTlRFTlQiKQp9OwoKKDp+CiA6IDxwPlRyaWVzIHRvIGZldGNoIHRoZSByZXNvdXJjZSByZWZlcnJlZCB0byBieSB0aGUgZ2l2ZW4gVVJJLjwvcD4KIDoKIDogPHA+SW4gb3JkZXIgdG8gcmV0cmlldmUgdGhlIGNvbnRlbnQsIHRoZSBmdW5jdGlvbnMgdXNlcyB0aGUKIDogVVJJIHJlc29sdXRpb24gYW5kIFVSTCByZXNvbHZlciBwcm9jZXNzIGFzIGRvY3VtZW50ZWQgYXQKIDogPGEgaHJlZj0iLi4vLi4vaHRtbC91cmlyZXNvbHZlcnMuaHRtbCI+CiA6IFVSSSBSZXNvbHZlcnM8L2E+LiBUaGVyZWZvcmUsIGl0IHF1ZXJpZXMgYWxsIFVSSSBtYXBwZXJzCiA6IGFuZCByZXNvbHZlcnMgd2l0aCB0aGUgc3BlY2lmaWVkIGVudGl0eSBraW5kLjwvcD4KIDoKIDogPHA+VGhlIGZ1bmN0aW9uIGlzIGFubm90YXRlZCB3aXRoIHRoZSA8dHQ+YW46c3RyZWFtYWJsZTwvdHQ+CiA6IGFubm90YXRpb24sIHRoYXQgaXMgaXQgcmV0dXJucyBhIHN0cmVhbWFibGUgc3RyaW5nLiBBIHN0cmVhbWFibGUKIDogc3RyaW5nIGNhbiBvbmx5IGJlIGNvbnN1bWVkIG9uY2UuIFBsZWFzZSBzZWUgc2VjdGlvbiAiU3RyZWFtYWJsZSBTdHJpbmdzIgogOiBpbiB0aGUgPGEgaHJlZj0iLi4vLi4vaHRtbC9vcHRpb25zX2FuZF9hbm5vdGF0aW9ucy5odG1sIj4KIDogZG9jdW1lbnRhdGlvbiBvZiBab3JiYSdzIGFubm90YXRpb25zPC9hPi4KIDogPC9wPgogOgogOiBAcGFyYW0gJHVyaSB0aGUgcmVzb3VyY2UgdG8gZmV0Y2guCiA6IEBwYXJhbSAkZW50aXR5S2luZCB0aGUga2luZCBvZiByZXNvdXJjZSB0byBmZXRjaC4KIDogQHJldHVybiB0aGUgcmVzb3VyY2UgcmVmZXJyZWQgdG8gYnkgdGhlIGdpdmVuIFVSSSBhcyBzdHJlYW1ibGUgc3RyaW5nLgogOgogOiBAZXJyb3IgemVycjpaWFFQMDAyNSBpZiB0aGUgVVJJIGNvdWxkIG5vdCBiZSByZXNvbHZlZAogOiAgIG9yIGRpZCBub3QgcmVzb2x2ZSB0byBhIDx0dD5TdHJlYW1SZXNvdXJjZTwvdHQ+LgogOgogOiBAc2VlIDxhIGhyZWY9Ii4uLy4uL2h0bWwvdXJpcmVzb2x2ZXJzLmh0bWwiPlVSSSBSZXNvbHZlcnM8L2E+LgogOiBAc2VlIDxhIGhyZWY9Ii4uLy4uL2h0bWwvb3B0aW9uc19hbmRfYW5ub3RhdGlvbnMuaHRtbCI+RG9jdW1lbnRhdGlvbiBvZiBab3JiYSdzIGFubm90YXRpb25zPC9hPi4KIDopCmRlY2xhcmUgJWFuOnN0cmVhbWFibGUgZnVuY3Rpb24gZmV0Y2g6Y29udGVudCgkdXJpIGFzIHhzOnN0cmluZywgJGVudGl0eUtpbmQgYXMgeHM6c3RyaW5nKQphcyB4czpzdHJpbmcKewogIGZldGNoOmNvbnRlbnQoJHVyaSwgJGVudGl0eUtpbmQsICJVVEYtOCIpCn07CgooOn4KIDopCmRlY2xhcmUgJWFuOnN0cmVhbWFibGUgZnVuY3Rpb24gZmV0Y2g6Y29udGVudCgKICAkdXJpIGFzIHhzOnN0cmluZywKICAkZW50aXR5S2luZCBhcyB4czpzdHJpbmcsCiAgJGVuY29kaW5nIGFzIHhzOnN0cmluZykKYXMgeHM6c3RyaW5nIGV4dGVybmFsOwoKKDp+CiA6KQpkZWNsYXJlICVhbjpzdHJlYW1hYmxlIGZ1bmN0aW9uIGZldGNoOmNvbnRlbnQtYmluYXJ5KCR1cmkgYXMgeHM6c3RyaW5nKSBhcyB4czpiYXNlNjRCaW5hcnkKewogIGZldGNoOmNvbnRlbnQtYmluYXJ5KCR1cmksICJTT01FX0NPTlRFTlQiKQp9OwoKKDp+CiA6KQpkZWNsYXJlICVhbjpzdHJlYW1hYmxlIGZ1bmN0aW9uIGZldGNoOmNvbnRlbnQtYmluYXJ5KCR1cmkgYXMgeHM6c3RyaW5nLCAkZW50aXR5S2luZCBhcyB4czpzdHJpbmcpCmFzIHhzOmJhc2U2NEJpbmFyeSBleHRlcm5hbDsK
\ No newline at end of file

=== added file 'test/rbkt/ExpQueryResults/zorba/fetch/fetch_some_transcode.xml.res'
--- test/rbkt/ExpQueryResults/zorba/fetch/fetch_some_transcode.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/fetch/fetch_some_transcode.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+äöü

=== added file 'test/rbkt/Queries/zorba/base64/decode_iso-8859-1.xq'
--- test/rbkt/Queries/zorba/base64/decode_iso-8859-1.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/base64/decode_iso-8859-1.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,3 @@
+import module namespace b = "http://www.zorba-xquery.com/modules/converters/base64";;
+
+b:decode(xs:base64Binary("5Pb8Cg=="), "ISO-8859-1")

=== added file 'test/rbkt/Queries/zorba/base64/decode_iso-8859-1_file.xq'
--- test/rbkt/Queries/zorba/base64/decode_iso-8859-1_file.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/base64/decode_iso-8859-1_file.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,5 @@
+import module namespace f = "http://expath.org/ns/file";;
+import module namespace b = "http://www.zorba-xquery.com/modules/converters/base64";;
+
+b:decode(xs:base64Binary(f:read-text(resolve-uri("iso-8859-1.txt"))), "ISO-8859-1")
+

=== added file 'test/rbkt/Queries/zorba/base64/iso-8859-1.txt'
--- test/rbkt/Queries/zorba/base64/iso-8859-1.txt	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/base64/iso-8859-1.txt	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+5Pb8Cg==
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/base64/reuse-stream.xq'
--- test/rbkt/Queries/zorba/base64/reuse-stream.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/base64/reuse-stream.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,16 @@
+(: From bug 996084. We need to ensure that a streamable base64 item can be re-used. :)
+
+import module namespace base64="http://www.zorba-xquery.com/modules/converters/base64";;
+import module namespace hash = "http://www.zorba-xquery.com/modules/cryptography/hash";;
+import module namespace file = "http://expath.org/ns/file";;
+
+declare variable $filename as xs:anyURI := resolve-uri("decoded");
+
+let $data as xs:base64Binary := file:read-binary ($filename)
+let $md5 as xs:string := hash:md5(base64:decode($data))
+
+return 
+  <file>
+    <content>{$data}</content>
+    <md5>{$md5}</md5>
+  </file>

=== added file 'test/rbkt/Queries/zorba/fetch/fetch_binary_1.xq'
--- test/rbkt/Queries/zorba/fetch/fetch_binary_1.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/fetch_binary_1.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,4 @@
+(: Fetch a random file from the filesystem :)
+import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch#2.0";;
+
+fetch:content-binary("http://www.zorba-xquery.com/modules/fetch";, "MODULE")

=== added file 'test/rbkt/Queries/zorba/fetch/fetch_seekable.xml.res'
--- test/rbkt/Queries/zorba/fetch/fetch_seekable.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/fetch_seekable.xml.res	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+true true true

=== added file 'test/rbkt/Queries/zorba/fetch/fetch_seekable.xq'
--- test/rbkt/Queries/zorba/fetch/fetch_seekable.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/fetch_seekable.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,8 @@
+import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch#2.0";;
+
+import module namespace s = "http://www.zorba-xquery.com/modules/string";;
+
+(: make sure the returned string is streamable and can be consumed twice, i.e. is seekable :)
+let $x := fetch:content("http://www.zorba-xquery.com/modules/fetch";, "MODULE")
+return (s:is-streamable($x), string-length($x) gt 0, string-length($x) gt 0)
+

=== added file 'test/rbkt/Queries/zorba/fetch/fetch_seekable_binary.xq'
--- test/rbkt/Queries/zorba/fetch/fetch_seekable_binary.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/fetch_seekable_binary.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,8 @@
+import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch#2.0";;
+
+import module namespace b = "http://www.zorba-xquery.com/modules/converters/base64";;
+
+(: make sure the returned string is streamable and can be consumed twice, i.e. is seekable :)
+let $x := fetch:content-binary("http://www.zorba-xquery.com/modules/fetch";, "MODULE")
+return (b:decode($x), $x)
+

=== added file 'test/rbkt/Queries/zorba/fetch/fetch_some_transcode.xq'
--- test/rbkt/Queries/zorba/fetch/fetch_some_transcode.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/fetch_some_transcode.xq	2012-05-09 00:52:21 +0000
@@ -0,0 +1,3 @@
+import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch#2.0";;
+
+fetch:content(resolve-uri("iso-8859-1.txt"), "SOME_CONTENT", "ISO-8859-1")

=== added file 'test/rbkt/Queries/zorba/fetch/iso-8859-1.txt'
--- test/rbkt/Queries/zorba/fetch/iso-8859-1.txt	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/fetch/iso-8859-1.txt	2012-05-09 00:52:21 +0000
@@ -0,0 +1,1 @@
+�


Follow ups