2009/dap/file-system file-writer.html,NONE,1.1

Update of /sources/public/2009/dap/file-system
In directory hutz:/tmp/cvs-serv7261

Added Files:
	file-writer.html 
Log Message:
first stab at a brain dump on File Writer

--- NEW FILE: file-writer.html ---
<!DOCTYPE html>
<html>
  <head>
    <title>File API: Writer</title>
    <meta http-equiv='Content-Type' content='text/html;charset=utf-8'/>
    <script src='../ReSpec.js/js/respec.js' class='remove'></script>
    <script class='remove'>
      var respecConfig = {
          specStatus:           "ED",
          shortName:            "file-writer-api",
          // publishDate:  "2009-08-06",
          // previousPublishDate:  "1977-03-15",
          edDraftURI:           "http://dev.w3.org/2009/dap/file-system/file-writer.html",
          // lcEnd: "2009-08-05",
          noIDLIn:  true,
          editors: [
                {   name:       "Robin Berjon",
                    url:        "http://berjon.com/",
                    company:    "Vodafone",
                    companyURL: "http://vodafone.com/" },
          ],
      };
    </script>
    <script src='../common/config.js' class='remove'></script>
  </head>
  <body>
    <section id='abstract'>
      This specification defines an <acronym title='Application Programming Interface'>API</acronym>
      to write to files.
      <!-- 
      XXX
      explain how it fits with File API
      -->
    </section>
    
    <section id='conformance'>
      <p>
        This specification defines conformance criteria that apply to a single product:
        <dfn>user agents</dfn> that implement the interfaces that it contains.
      </p>
      <div class='issue'>
        <p>
          If different user agents obtain writers in different ways we will need
          to add more classes, or some way to handle the variability.
        </p>
      </div>
    </section>
    
    <section class='informative'>
      <h2>Introduction</h2>
      <p>
        ...
      </p>
      <!-- 
        XXX
        be clear that it may be remote writing sources
        be clear that it may look different from typical to fit inside security constraints
        - look at cut and paste
        - look at BinaryArray
        - go over emails on WebApps about use cases again
      -->
      <section>
        <h2>General Issues</h2>
        <div class='issues'>
          <p>
            Do we need async writers? There are further details about options for this below.
          </p>
          <p>
            Do we need a way to remove chars/bytes from the middle of a file without
            rewriting it completely?
          </p>
          <p>
            We need to add a lot of definitions, and generally tighten up the prose.
          </p>
        </div>
      </section>
      
      <section>
        <h2>Examples</h2>
        <p>
          Here is a simple comment that writes a text file:
        </p>
        <pre class='example sh_javascript'>
          function sucCB (tw) {
              for (var i = 0; i &lt; 10; i++) {
                  tw.print("I am dahut number " . i . "\n");
              }
              tw.close();
          }
          function errCB (err) {
              alert("There was an error opening the file.");
          }
          navigator.device.textWriter("text/plain", sucCB, "dahut.txt", { endings: "crlf" }, errCB);
        </pre>
      </section>
    </section>
    
    <section>
      <h2>Obtaining file writers</h2>
      <p>
        There are several ways in which writer can be obtained. Not all <a>user agents</a> may in 
        fact implement all of them.
      </p>
      <section class='informative'>
        <h2>Security Considerations</h2>
        <p>
          Within a browser <a>user agent</a>, the request for a writer through the <a>Device</a> API
          may for instance trigger a dialog very similar to the one users see when downloading a file,
          which in turn can cause a file save dialog to show. Relying on a common metaphor with similar
          security issues can help make sure that users are as cautious as they are with downloaded file,
          and helps reuse the existing checking toolset.
        </p>
        <p>
          Most of the security issues pertaining to writing to a file on the user's drive are the
          same as the ones involved in downloading arbitrary files from the Internet. The primary
          difference stems from the fact that the file may be continuously written and re-written,
          at least until such a time as it is deemed closed by the user agent. This has an impact on
          size quota on one side, and on processes that may require analysing the content of the file.
        </p>
        <p>
          So long as <code>save</code> has not been called on the writer object and there are modifications
          being made to the file, the <a>user agent</a> should keep the content in a separate temporary file
          as sometimes happens during download. Upon calling <code>save</code>, the temporary file would replace
          the permanent one. If the <a>user agent</a> runs a security mechanism such as a virus checker, this
          step is likely the right one to do so.
        </p>
        <p>
          Where quotas are concerned, <a>user agents</a> should monitor the size of the file(s) being written
          and possibly interrupt the script and warn the user if certain limits of file size or remaining
          space are reached.
        </p>
        <p>
          Other parts of the download protection tool-chain such as flagging files as "unsafe to open" or
          refusing to create dangerous file names (or file names with extensions that do not match the
          media type) should naturally be applied.
        </p>
      </section>
      <section>
        <h2>Requesting writers from the Device interface</h2>
        <section>
          <h2>The <code>Device</code> interface</h2>
          <p>
            The <a>Device</a> interface is typically exposed on the <code>navigator.device</code> object,
            as defined in [[!CORE-DEVICE]].
          </p>
          <div class='idl' title='Device implements DeviceWriter'></div>
          <dl title='[Supplemental, NoInterfaceObject] interface DeviceWriter' class='idl'>
            <dt>PendingOp textWriter ()</dt>
            <dd>
              <p>
                This method is used to request a writer for text documents. It begins an asynchronous
                process that results either in obtaining the right to write to a file (in which case
                <code>twCB</code> is called), or in that request being denied (in which case <code>errCB</code>
                is called).
              </p>
              <dl class='parameters'>
                <dt>DOMString mediaType</dt>
                <dd>
                  This is the media type that describes the content of the file, without media type
                  parameters. If it is an invalid media type, or if it has parameters, the operation
                  MUST abort and call the <code>errCB</code> callback.
                </dd>
                <dt>TextWriterCB twCB</dt>
                <dd>
                  The callback that is called when the writer is accepted.
                </dd>
                <dt>optional DOMString name</dt>
                <dd>
                  The name of the file (without any path component). The <a>user agent</a> MAY choose
                  to ignore this choice of name, or to modify it.
                </dd>
                <dt>optional TextOptions opt</dt>
                <dd>
                  Options that define how the text is written.
                </dd>
                <dt>optional ErrorCB errCB</dt>
                <dd>
                  A callback that is called when errors happen, or when the request to obtain a file
                  writer is denied.
                </dd>
              </dl>
            </dd>
            <dt>PendingOp binaryWriter ()</dt>
            <dd>
              <p>
                This method is used to request a writer for binary documents.
              </p>
              <dl class='parameters'>
                <dt>DOMString mediaType</dt>
                <dd>
                  This is the media type that describes the content of the file, without media type
                  parameters. If it is an invalid media type, or if it has parameters, the operation
                  MUST abort and call the <code>errCB</code> callback.
                </dd>
                <dt>BinaryWriterCB bwCB</dt>
                <dd>
                  The callback that is called when the writer is accepted.
                </dd>
                <dt>optional DOMString name</dt>
                <dd>
                  The name of the file (without any path component). The <a>user agent</a> MAY choose
                  to ignore this choice of name, or to modify it.
                </dd>
                <dt>optional ErrorCB errCB</dt>
                <dd>
                  A callback that is called when errors happen, or when the request to obtain a file
                  writer is denied.
                </dd>
              </dl>
            </dd>
          </dl>
        </section>
        <section>
          <h2>The <code>TextOptions</code> interface</h2>
          <p>
            The following interface is used to specify options for textual writing:
          </p>
          <dl title='[NoInterfaceObject] interface TextOptions' class='idl'>
            <dt>attribute DOMString endings</dt>
            <dd>
              <p>
                How strings containing <code>\n</code> are to be written out. There possible values are:
              </p>
              <table class='simple'>
                <tr><th>Value</th><th>Description</th></tr>
                <tr>
                  <td>transparent</td>
                  <td>
                    Code points from the string remain untouched. This is the default value.
                  </td>
                </tr>
                <tr>
                  <td>native</td>
                  <td>
                    Line-endings are handled according to the platform's preference.
                  </td>
                </tr>
                <tr>
                  <td>lf</td>
                  <td>
                    A <code>LF</code> is used. This is the same as is used in Unix systems, as well as Apple OS X.
                  </td>
                </tr>
                <tr>
                  <td>cr</td>
                  <td>
                    A <code>CR</code> is used. This is the same as was used in antique Macintosh systems.
                  </td>
                </tr>
                <tr>
                  <td>crlf</td>
                  <td>
                    A <code>CRLF</code> pair is used. This is the same as on Microsoft Windows systems.
                  </td>
                </tr>
              </table>
            </dd>
            <dt>attribute DOMString encoding</dt>
            <dd>
              <p>
                The encoding that is used to write out to the file. The default value is <code>UTF-8</code>.
                A <a>user agent</a> is not required to support other encodings.
              </p>
              <div class='issue'>
                <p>
                  It may be preferable if we required support for UTF-16 BE/LE, and perhaps for ISO-8859-1
                  as well (especially if they're supported anyway).
                </p>
              </div>
            </dd>
          </dl>
        </section>
        <section>
          <h2>The <code>TextWriterCB</code> interface</h2>
          <p>
            When <code>textWriter()</code> succeeds, the following callback is made:
          </p>
          <dl title='[NoInterfaceObject, Callback=FunctionOnly] interface TextWriterCB' class='idl'>
            <dt>void onSuccess ()</dt>
            <dd>
              <p>
                The writer was successfully obtained.
              </p>
              <dl class='parameters'>
                <dt>TextWriter tw</dt>
                <dd>
                  The writer to be used.
                </dd>
              </dl>
            </dd>
          </dl>
        </section>
        <section>
          <h2>The <code>BinaryWriterCB</code> interface</h2>
          <p>
            When <code>binaryWriter()</code> succeeds, the following callback is made:
          </p>
          <dl title='[NoInterfaceObject, Callback=FunctionOnly] interface BinaryWriterCB' class='idl'>
            <dt>void onSuccess ()</dt>
            <dd>
              <p>
                The writer was successfully obtained.
              </p>
              <dl class='parameters'>
                <dt>BinaryWriter bw</dt>
                <dd>
                  The writer to be used.
                </dd>
              </dl>
            </dd>
          </dl>
        </section>
        <section>
          <h2>The <code>ErrorCB</code> interface</h2>
          <p>
            When either <code>textWriter()</code> or <code>binaryWriter()</code> fails, or when a bad parameter
            is passed to them, the following callback is made:
          </p>
          <dl title='[NoInterfaceObject, Callback=FunctionOnly] interface ErrorCB' class='idl'>
            <dt>void onError ()</dt>
            <dd>
              <p>
                The writer was not obtained, either because invalid parameters were provided, or because the
                request to obtain a writer was denied.
              </p>
              <dl class='parameters'>
                <dt>WriterError err</dt>
                <dd>
                  The error that was generated.
                </dd>
              </dl>
            </dd>
          </dl>
        </section>
        <section>
          <h2>The <code>WriterError</code> interface</h2>
          <p>
            The error is defined as follows:
          </p>
          <dl title='[NoInterfaceObject] interface WriterError' class='idl'>
            <dt>const unsigned short DENIED_ERR = 1</dt>
            <dd>
              The request to obtain a writer was denied.
            </dd>
            <dt>const unsigned short MEDIA_TYPE_ERR = 2</dt>
            <dd>
              The provided media type was invalid, or contained media type parameters.
            </dd>
            <dt>readonly attribute unsigned short code</dt>
            <dd>
              The code specifying the type of this error.
            </dd>
          </dl>
        </section>
      </section>
      <section>
        <h2>Obtaining a writer through an input element</h2>
        <p>
          An additional <code>writable</code> attribute is added to [[!HTML5]] <code>input</code>
          elements in the <a href='http://dev.w3.org/html5/spec/forms.html#file-upload-state'>file upload state</a>.
          When present, the <a>user agent</a> SHOULD provide an interface similar to that which is
          used for regular file upload, and MUST provide a way for the user to accept making the file
          writable (e.g. by providing a check box enabling it, unchecked by default).
        </p>
        <p>
          The values of the <code>writable</code> attribute are "text" and "binary". If the attribute
          is present but with a value other than these, the <a>user agent</a> MUST ignore it.
        </p>
        <p>
          If the writability of the files has been accepted, the <a>user agent</a> MUST produce
          a <code>FileList</code> as per [[!FILE-API]], and items in the <code>FileList</code>
          MUST be of type <a>TextWriter</a> or <a>BinaryWriter</a> if the value of <code>writable</code>
          was "text" or binary, respectively.
        </p>
        <div class='issue'>
          <p>
            It is not clear that this way of selecting between text and binary is good. We could perhaps
            provide an "auto" value that would use the file type; or just make <code>writable</code> a boolean
            attribute, return <a>FileWriter</a>s in the <code>FileList</code>, and provide a way of casting.
          </p>
        </div>
        <div class='issue'>
          <p>
            This is not necessarily very elegant. Another option would be to not touch input at all,
            and in order to address the use case of loading a file to be saved provide variants of
            <code>textWriter</code> and <code>binaryWriter</code> that could take the file object
            and go through the download prompting defaulting to that file being selected, with the
            "Careful you're going to overwrite" well-known platform prompt. It would likely render the
            name and mediaType parameters useless.
          </p>
        </div>
      </section>
      <section>
        <h2>Integration with cut &amp; paste and drag &amp; drop</h2>
        <!-- XXX TBD -->
        <div class='issue'>
          <p>@@ TDB @@</p>
        </div>
      </section>
    </section>
    
    <section>
      <h2>File Writing Interfaces</h2>
      <section>
        <h2>The <code>FileWriter</code> interface</h2>
        <p>
          This interface is never accessed directly, but serves as the base class for
          <a>TextWriter</a> and <a>BinaryWriter</a>. It inherits from the <code>File</code>
          interface defined in [[!FILE-API]].
        </p>
        <dl title='[NoInterfaceObject] interface FileWriter : File' class='idl'>
          <dt>readonly attribute unsigned long long length</dt>
          <dd>
            The size of the file in characters for <a>TextWriter</a> and bytes for <a>BinaryWriter</a>.
          </dd>
          <dt>readonly attribute unsigned long long position</dt>
          <dd>
            The current writing position in the file, measured in characters for <a>TextWriter</a> and 
            bytes for <a>BinaryWriter</a>.
          </dd>
          <dt>void seek ()</dt>
          <dd>
            <p>
              Place the current position in the file to the specified value. Subsequent writes will
              insert their content at that position.
            </p>
            <dl class='parameters'>
              <dt>long long position</dt>
              <dd>
                The new position to which to seek, measured in characters for <a>TextWriter</a> and bytes 
                for <a>BinaryWriter</a>. If it is negative, it is counted backwards from the end of 
                the file. If it is positive and superior to <code>length</code>, it is set to the end 
                of the file. If it is negative and absolutely superior to <code>length</code>, it is
                set to 0.
              </dd>
            </dl>
          </dd>
          <dt>void truncate ()</dt>
          <dd>
            <p>
              Truncates the file such that its size is reduced to that which is specified, the remaining
              content being discarded.
            </p>
            <dl class='parameters'>
              <dt>unsigned long long size</dt>
              <dd>
                The size to which the file is truncated, measured in characters for <a>TextWriter</a> 
                and bytes for <a>BinaryWriter</a>. If it is greater than <code>length</code>,
                nothing happens.
              </dd>
            </dl>
          </dd>
          <dt>readonly attribute boolean saved</dt>
          <dd>
            Indicates whether the file is in a saved state or not. When a writer is created, this is set to
            <code>false</code>, and is further reset to <code>false</code> whenever a write operation is
            performed. It is set to <code>true</code> after a call to <code>save()</code>.
          </dd>
          <dt>void save ()</dt>
          <dd>
            <p>
              Indicate that the file is in a consistent state and good to be read. This does not close the
              file as more data may yet be written, but it marks it as usable.
            </p>
            <div class='issue'>
              <p>
                Should this be asynchronous so that networked files (or simply slow supports) can be supported
                with writes being synched regularly? Should it be renamed <code>sync</code> (and likewise for
                <code>saved</code>/<code>synched</code>)?
              </p>
            </div>
          </dd>
          <dt>readonly attribute boolean open</dt>
          <dd>
            Indicates whether the file is open and therefore may be written to. When the writer is created,
            this is set to <code>true</code>. It is switched to <code>false</code> after a call to <code>close()</code>,
            after which point write operations raise exceptions.
          </dd>
          <dt>void close ()</dt>
          <dd>
            <p>
              Indicate that the file will no longer be written to. Implies <code>save()</code>.
            </p>
            <div class='issue'>
              <p>
                If <code>save()</code> becomes async, then this does too.
              </p>
            </div>
          </dd>
        </dl>
      </section>
      <section>
        <h2>The <code>TextWriter</code> interface</h2>
        <p>
          This interface is used to write to textual files.
        </p>
        <dl title='[NoInterfaceObject] interface TextWriter : FileWriter' class='idl'>
          <dt>void print ()</dt>
          <dd>
            <p>
              Writes the supplied characters at the current file position, using the encoding and line-endings
              defined in <a>TextOptions</a>.
            </p>
            <dl class='parameters'>
              <dt>DOMString text</dt>
              <dd>
                The text to be written.
              </dd>
            </dl>
            <dl class='exception' title='WriteException'>
              <dt>FILE_CLOSED_ERR</dt>
              <dd>
                The file is closed and therefore cannot be written to.
              </dd>
            </dl>
          </dd>
        </dl>
      </section>
      <section>
        <h2>The <code>BinaryWriter</code> interface</h2>
        <p>
          This interface is used to write to binary files, using the <code>Blob</code> interface
          defined in [[!FILE-API]].
        </p>
        <dl title='[NoInterfaceObject] interface BinaryWriter : FileWriter' class='idl'>
          <dt>void write ()</dt>
          <dd>
            <p>
              Writes the supplied bytes at the current file position.
            </p>
            <dl class='parameters'>
              <dt>Blob data</dt>
              <dd>
                The data to be written.
              </dd>
            </dl>
            <dl class='exception' title='WriteException'>
              <dt>FILE_CLOSED_ERR</dt>
              <dd>
                The file is closed and therefore cannot be written to.
              </dd>
            </dl>
          </dd>
        </dl>
      </section>
      <section>
        <h2>The <code>WriteException</code> exception</h2>
        <p>
          This exception can be raised with different codes on write operations.
        </p>
        <dl title='[NoInterfaceObject] exception WriteException' class='idl'>
          <dt>const unsigned short FILE_CLOSED_ERR = 1</dt>
          <dd>
            An attempt to write was made to a file that is closed.
          </dd>
        </dl>
      </section>
    </section>
    
    <section class='appendix'>
      <h2>Acknowledgements</h2>
      <p>
        Many thanks to OMTP BONDI who provided input for this API, based on an initial effort by Opera,
        and to Arun for his excellent work on the File API.
      </p>
    </section>
  </body>
</html>

Received on Thursday, 3 December 2009 17:38:36 UTC