Back to index

lightning-sunbird  0.9+nobinonly
Classes | Public Types | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes
nsMorkReader Class Reference

#include <nsMorkReader.h>

Collaboration diagram for nsMorkReader:
Collaboration graph
[legend]

List of all members.

Classes

class  IDKey
class  IDString
struct  MorkColumn

Public Types

typedef nsDataHashtable< IDKey,
nsCString
StringMap
typedef nsDataHashtable< IDKey,
PRInt32
IndexMap
typedef PLDHashOperator(* PR_CALLBACK )(const nsCSubstring &rowID, const nsTArray< nsCString > *values, void *userData)

Public Member Functions

nsresult Init ()
nsresult Read (nsIFile *aFile)
const nsTArray< MorkColumn > & GetColumns () const
void EnumerateRows (RowEnumerator aCallback, void *aUserData) const
const nsTArray< nsCString > * GetMetaRow () const
void NormalizeValue (nsCString &aValue) const
 nsMorkReader ()
 ~nsMorkReader ()

Private Member Functions

nsresult ParseMap (const nsCSubstring &aLine, StringMap *aMap)
nsresult ParseTable (const nsCSubstring &aLine, const IndexMap &aColumnMap)
nsresult ReadLine (nsCString &aLine)

Static Private Member Functions

static nsTArray< nsCString > * NewVoidStringArray (PRInt32 aSize)

Private Attributes

nsTArray< MorkColumnmColumns
StringMap mValueMap
nsAutoPtr< nsTArray< nsCString > > mMetaRow
nsDataHashtable< IDKey,
nsTArray< nsCString > * > 
mTable
nsCOMPtr< nsILineInputStreammStream
nsCString mEmptyString

Detailed Description

Definition at line 56 of file nsMorkReader.h.


Member Typedef Documentation

Definition at line 109 of file nsMorkReader.h.

Definition at line 132 of file nsMorkReader.h.

Definition at line 105 of file nsMorkReader.h.


Constructor & Destructor Documentation

Definition at line 159 of file nsMorkReader.h.

{}

Definition at line 157 of file nsMorkReader.cpp.

Here is the call graph for this function:


Member Function Documentation

void nsMorkReader::EnumerateRows ( RowEnumerator  aCallback,
void aUserData 
) const

Definition at line 260 of file nsMorkReader.cpp.

{
  // Constify the table values
  typedef const nsDataHashtable<IDKey, const nsTArray<nsCString>* > ConstTable;
  NS_REINTERPRET_CAST(ConstTable*, &mTable)->EnumerateRead(aCallback,
                                                           aUserData);
}

Definition at line 144 of file nsMorkReader.h.

{ return mColumns; }

Definition at line 153 of file nsMorkReader.h.

{ return mMetaRow; }

Definition at line 141 of file nsMorkReader.cpp.

Here is the call graph for this function:

nsTArray< nsCString > * nsMorkReader::NewVoidStringArray ( PRInt32  aSize) [static, private]

Definition at line 567 of file nsMorkReader.cpp.

{
  nsAutoPtr< nsTArray<nsCString> > array(new nsTArray<nsCString>(aCount));
  NS_ENSURE_TRUE(array, nsnull);

  for (PRInt32 i = 0; i < aCount; ++i) {
    nsCString *elem = array->AppendElement();
    NS_ENSURE_TRUE(elem, nsnull);
    elem->SetIsVoid(PR_TRUE);
  }

  return array.forget();
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 547 of file nsMorkReader.cpp.

{
  PRUint32 len = aValue.Length();
  if (len == 0) {
    return;
  }
  const nsCSubstring &str = Substring(aValue, 1, len - 1);
  char c = aValue[0];
  if (c == '^') {
    if (!mValueMap.Get(str, &aValue)) {
      aValue.Truncate(0);
    }
  } else if (c == '=') {
    aValue.Assign(str);
  } else {
    aValue.Truncate(0);
  }
}

Here is the call graph for this function:

nsresult nsMorkReader::ParseMap ( const nsCSubstring aLine,
StringMap aMap 
) [private]

Definition at line 272 of file nsMorkReader.cpp.

{
  nsCLineString line(aLine);
  nsCAutoString key;
  nsresult rv = NS_OK;

  // If the first line is the a=c line (column map), just skip over it.
  if (StringBeginsWith(line, NS_LITERAL_CSTRING("< <(a=c)>"))) {
    rv = ReadLine(line);
  }

  for (; NS_SUCCEEDED(rv); rv = ReadLine(line)) {
    PRUint32 idx = 0;
    PRUint32 len = line.Length();
    PRUint32 tokenStart;

    while (idx < len) {
      switch (line[idx++]) {
      case '(':
        // Beginning of a key/value pair
        if (!key.IsEmpty()) {
          NS_WARNING("unterminated key/value pair?");
          key.Truncate(0);
        }

        tokenStart = idx;
        while (idx < len && line[idx] != '=') {
          ++idx;
        }
        key = Substring(line, tokenStart, idx - tokenStart);
        break;
      case '=':
        {
          // Beginning of the value
          if (key.IsEmpty()) {
            NS_WARNING("stray value");
            break;
          }

          tokenStart = idx;
          while (idx < len && line[idx] != ')') {
            if (line[idx] == '\\') {
              ++idx; // skip escaped ')' characters
            }
            ++idx;
          }
          PRUint32 tokenEnd = PR_MIN(idx, len);
          ++idx;

          nsCString value;
          MorkUnescape(Substring(line, tokenStart, tokenEnd - tokenStart),
                       value);
          aMap->Put(key, value);
          key.Truncate(0);
          break;
        }
      case '>':
        // End of the map.
        NS_WARN_IF_FALSE(key.IsEmpty(),
                         "map terminates inside of key/value pair");
        return NS_OK;
      }
    }
  }

  // We ran out of lines and the map never terminated.  This probably indicates
  // a parsing error.
  NS_WARNING("didn't find end of key/value map");
  return NS_ERROR_FAILURE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsMorkReader::ParseTable ( const nsCSubstring aLine,
const IndexMap aColumnMap 
) [private]

Definition at line 349 of file nsMorkReader.cpp.

{
  nsCLineString line(aLine);
  const PRUint32 columnCount = mColumns.Length(); // total number of columns

  PRInt32 columnIndex = -1; // column index of the cell we're parsing
  // value array for the row we're parsing
  nsTArray<nsCString> *currentRow = nsnull;
  PRBool inMetaRow = PR_FALSE;

  do {
    PRUint32 idx = 0;
    PRUint32 len = line.Length();
    PRUint32 tokenStart, tokenEnd;

    while (idx < len) {
      switch (line[idx++]) {
      case '{':
        // This marks the beginning of a table section.  There's a lot of
        // junk before the first row that looks like cell values but isn't.
        // Skip to the first '['.
        while (idx < len && line[idx] != '[') {
          if (line[idx] == '{') {
            inMetaRow = PR_TRUE; // the meta row is enclosed in { }
          } else if (line[idx] == '}') {
            inMetaRow = PR_FALSE;
          }
          ++idx;
        }
        break;
      case '[':
        {
          // Start of a new row.  Consume the row id, up to the first '('.
          // Row edits also have a table namespace, separated from the row id
          // by a colon.  We don't make use of the namespace, but we need to
          // make sure not to consider it part of the row id.
          if (currentRow) {
            NS_WARNING("unterminated row?");
            currentRow = nsnull;
          }

          // Check for a '-' at the start of the id.  This signifies that
          // if the row already exists, we should delete all columns from it
          // before adding the new values.
          PRBool cutColumns;
          if (idx < len && line[idx] == '-') {
            cutColumns = PR_TRUE;
            ++idx;
          } else {
            cutColumns = PR_FALSE;
          }

          tokenStart = idx;
          while (idx < len &&
                 line[idx] != '(' &&
                 line[idx] != ']' &&
                 line[idx] != ':') {
            ++idx;
          }
          tokenEnd = idx;
          while (idx < len && line[idx] != '(' && line[idx] != ']') {
            ++idx;
          }
          
          if (inMetaRow) {
            mMetaRow = NewVoidStringArray(columnCount);
            NS_ENSURE_TRUE(mMetaRow, NS_ERROR_OUT_OF_MEMORY);
            currentRow = mMetaRow;
          } else {
            const nsCSubstring& row = Substring(line, tokenStart,
                                                tokenEnd - tokenStart);
            if (!mTable.Get(row, &currentRow)) {
              currentRow = NewVoidStringArray(columnCount);
              NS_ENSURE_TRUE(currentRow, NS_ERROR_OUT_OF_MEMORY);

              NS_ENSURE_TRUE(mTable.Put(row, currentRow),
                             NS_ERROR_OUT_OF_MEMORY);
            }
          }
          if (cutColumns) {
            // Set all of the columns to void
            // (this differentiates them from columns which are empty strings).
            for (PRUint32 i = 0; i < columnCount; ++i) {
              currentRow->ElementAt(i).SetIsVoid(PR_TRUE);
            }
          }
          break;
        }
      case ']':
        // We're done with the row
        currentRow = nsnull;
        inMetaRow = PR_FALSE;
        break;
      case '(':
        {
          if (!currentRow) {
            NS_WARNING("cell value outside of row");
            break;
          }

          NS_WARN_IF_FALSE(columnIndex == -1, "unterminated cell?");

          PRBool columnIsAtom;
          if (line[idx] == '^') {
            columnIsAtom = PR_TRUE;
            ++idx; // this is not part of the column id, advance past it
          } else {
            columnIsAtom = PR_FALSE;
          }
          tokenStart = idx;
          while (idx < len && line[idx] != '^' && line[idx] != '=') {
            if (line[idx] == '\\') {
              ++idx; // skip escaped characters
            }
            ++idx;
          }

          tokenEnd = PR_MIN(idx, len);

          nsCAutoString column;
          const nsCSubstring &colValue =
            Substring(line, tokenStart, tokenEnd - tokenStart);
          if (columnIsAtom) {
            column.Assign(colValue);
          } else {
            MorkUnescape(colValue, column);
          }

          if (!aColumnMap.Get(colValue, &columnIndex)) {
            NS_WARNING("Column not in column map, discarding it");
            columnIndex = -1;
          }
        }
        break;
      case '=':
      case '^':
        {
          if (columnIndex == -1) {
            NS_WARNING("stray ^ or = marker");
            break;
          }

          PRBool valueIsAtom = (line[idx - 1] == '^');
          tokenStart = idx - 1;  // include the '=' or '^' marker in the value
          while (idx < len && line[idx] != ')') {
            if (line[idx] == '\\') {
              ++idx; // skip escaped characters
            }
            ++idx;
          }
          tokenEnd = PR_MIN(idx, len);
          ++idx;

          const nsCSubstring &value =
            Substring(line, tokenStart, tokenEnd - tokenStart);
          if (valueIsAtom) {
            (*currentRow)[columnIndex] = value;
          } else {
            nsCAutoString value2;
            MorkUnescape(value, value2);
            (*currentRow)[columnIndex] = value2;
          }
          columnIndex = -1;
        }
        break;
      }
    }
  } while (currentRow && NS_SUCCEEDED(ReadLine(line)));

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 189 of file nsMorkReader.cpp.

{
  nsCOMPtr<nsIFileInputStream> stream =
    do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID);
  NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);

  nsresult rv = stream->Init(aFile, PR_RDONLY, 0, 0);
  NS_ENSURE_SUCCESS(rv, rv);

  mStream = do_QueryInterface(stream);
  NS_ASSERTION(mStream, "file input stream must impl nsILineInputStream");

  nsCLineString line;
  rv = ReadLine(line);
  if (!line.EqualsLiteral("// <!-- <mdb:mork:z v=\"1.4\"/> -->")) {
    return NS_ERROR_FAILURE; // unexpected file format
  }

  IndexMap columnMap;
  NS_ENSURE_TRUE(columnMap.Init(), NS_ERROR_OUT_OF_MEMORY);

  while (NS_SUCCEEDED(ReadLine(line))) {
    // Trim off leading spaces
    PRUint32 idx = 0, len = line.Length();
    while (idx < len && line[idx] == ' ') {
      ++idx;
    }
    if (idx >= len) {
      continue;
    }

    const nsCSubstring &l = Substring(line, idx);

    // Look at the line to figure out what section type this is
    if (StringBeginsWith(l, NS_LITERAL_CSTRING("< <(a=c)>"))) {
      // Column map.  We begin by creating a hash of column id to column name.
      StringMap columnNameMap;
      NS_ENSURE_TRUE(columnNameMap.Init(), NS_ERROR_OUT_OF_MEMORY);

      rv = ParseMap(l, &columnNameMap);
      NS_ENSURE_SUCCESS(rv, rv);

      // Now that we have the list of columns, we put them into a flat array.
      // Rows will have value arrays of the same size, with indexes that
      // correspond to the columns array.  As we insert each column into the
      // array, we also make an entry in columnMap so that we can look up the
      // index given the column id.
      mColumns.SetCapacity(columnNameMap.Count());

      AddColumnClosure closure(&mColumns, &columnMap);
      columnNameMap.EnumerateRead(AddColumn, &closure);
      if (NS_FAILED(closure.result)) {
        return closure.result;
      }
    } else if (StringBeginsWith(l, NS_LITERAL_CSTRING("<("))) {
      // Value map
      rv = ParseMap(l, &mValueMap);
      NS_ENSURE_SUCCESS(rv, rv);
    } else if (l[0] == '{' || l[0] == '[') {
      // Table / table row
      rv = ParseTable(l, columnMap);
      NS_ENSURE_SUCCESS(rv, rv);
    } else {
      // Don't know, hopefully don't care
    }
  }

  return NS_OK;
}

Here is the call graph for this function:

nsresult nsMorkReader::ReadLine ( nsCString aLine) [private]

Definition at line 522 of file nsMorkReader.cpp.

{
  PRBool res;
  nsresult rv = mStream->ReadLine(aLine, &res);
  NS_ENSURE_SUCCESS(rv, rv);
  if (!res) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  while (!aLine.IsEmpty() &&  aLine.Last() == '\\') {
    // There is a continuation for this line.  Read it and append.
    nsCLineString line2;
    rv = mStream->ReadLine(line2, &res);
    NS_ENSURE_SUCCESS(rv, rv);
    if (!res) {
      return NS_ERROR_NOT_AVAILABLE;
    }
    aLine.Truncate(aLine.Length() - 1);
    aLine.Append(line2);
  }

  return NS_OK;
}

Here is the caller graph for this function:


Member Data Documentation

Definition at line 183 of file nsMorkReader.h.

Definition at line 188 of file nsMorkReader.h.

Definition at line 185 of file nsMorkReader.h.

Definition at line 187 of file nsMorkReader.h.

Definition at line 186 of file nsMorkReader.h.

Definition at line 184 of file nsMorkReader.h.


The documentation for this class was generated from the following files: