2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 using System.Collections.Generic;
21 using System.Threading;
23 namespace Tizen.Applications.DataControl
26 /// Represents MatrixCursor class for DataControl provider's matrix cursor.
28 public class MatrixCursor : IDisposable, ICursor
30 private const string LogTag = "Tizen.Applications.DataControl";
31 private FileStream _fs;
32 private bool _disposed = false;
33 private string _cursorPath;
34 private long _rowCount = 0;
35 private long _rowCountPosition = 0;
36 private int _currentRowIndex = 0;
37 private IList<long> _rowFieldOffset = new List<long>();
38 private string[] _columnNames;
39 private ColumnType[] _columnTypes;
40 private const int ColumnTypeNull = 5;
42 private byte[] GetValue(int index)
44 byte[] int_tmp = new byte[sizeof(int)];
51 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
52 if (read_len != int_tmp.Length)
54 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Type " + index.ToString());
57 type = (ColumnType)BitConverter.ToInt32(int_tmp, 0);
59 if (type != _columnTypes[index])
61 if ((int)type == ColumnTypeNull &&
62 (_columnTypes[index] == ColumnType.ColumnTypeBlob || _columnTypes[index] == ColumnType.ColumnTypeString))
64 return null; /* null type */
67 ErrorFactory.ThrowException(ResultType.IoError, true, "Type mismatch " + index.ToString());
70 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
71 if (read_len != int_tmp.Length)
73 ErrorFactory.ThrowException(ResultType.IoError, true, "Column size " + index.ToString());
76 size = BitConverter.ToInt32(int_tmp, 0);
80 ErrorFactory.ThrowException(ResultType.IoError, true, "Invalid data size " + index.ToString());
83 ret_array = new byte[size];
84 read_len = _fs.Read(ret_array, 0, ret_array.Length);
85 if (read_len != ret_array.Length)
87 ErrorFactory.ThrowException(ResultType.IoError, true, "Column value size " + index.ToString());
94 private void MoveToColumn(int ColumnIndex)
97 byte[] int_tmp = new byte[sizeof(int)];
101 seek_len = _fs.Seek(_rowFieldOffset[_currentRowIndex], SeekOrigin.Begin);
102 if (seek_len != _rowFieldOffset[_currentRowIndex])
104 ErrorFactory.ThrowException(ResultType.IoError, true, "Row index " + _currentRowIndex.ToString());
107 for (i = 0; i < ColumnIndex; i++)
109 /* type(int) size(int) value */
110 switch (_columnTypes[i])
112 case ColumnType.ColumnTypeInt:
113 tmp_position = sizeof(int) * 2 + sizeof(Int64);
114 _fs.Seek(tmp_position, SeekOrigin.Current);
116 case ColumnType.ColumnTypeDouble:
117 tmp_position = sizeof(int) * 2 + sizeof(double);
118 _fs.Seek(tmp_position, SeekOrigin.Current);
120 case ColumnType.ColumnTypeString:
121 tmp_position = sizeof(int);
122 _fs.Seek(tmp_position, SeekOrigin.Current);
123 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
124 if (read_len != int_tmp.Length)
126 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Index " + ColumnIndex.ToString());
129 tmp_position = BitConverter.ToInt32(int_tmp, 0);
131 if (tmp_position > 0)
133 _fs.Seek(tmp_position, SeekOrigin.Current);
137 case ColumnType.ColumnTypeBlob:
138 tmp_position = sizeof(int);
139 _fs.Seek(tmp_position, SeekOrigin.Current);
141 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
142 if (read_len != int_tmp.Length)
144 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Index " + ColumnIndex.ToString());
147 tmp_position = BitConverter.ToInt32(int_tmp, 0);
149 if (tmp_position > 0)
151 _fs.Seek(tmp_position, SeekOrigin.Current);
160 internal FileStream GetFileStream()
166 /// Gets column count of MatrixCursor.
168 public int GetColumnCount()
170 return _columnTypes.Length;
174 /// Returns the column type at the given zero-based column index.
176 /// <param name="index">Target column index</param>
177 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
178 public ColumnType GetColumnType(int index)
180 if (index < 0 || index >= _columnTypes.Length)
182 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
185 return _columnTypes[index];
189 /// Returns the column name at the given zero-based column index.
191 /// <param name="index">Target column index</param>
192 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
193 public string GetColumnName(int index)
195 if (index < 0 || index >= _columnTypes.Length)
197 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
200 return _columnNames[index];
204 /// Gets MatrixCursor's row count.
206 public long GetRowCount()
212 /// Move the MatrixCursor to the next row.
216 if (_currentRowIndex >= _rowCount - 1)
226 /// Move the MatrixCursor to the previous row.
230 if (_currentRowIndex <= 0)
240 /// Move the MatrixCursor to the first row.
244 _currentRowIndex = 0;
249 /// Returns the value of the requested column as a int.
251 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
252 public int GetIntValue(int index)
257 if (index < 0 || index >= _columnTypes.Length)
259 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
262 byte_array = GetValue(index);
263 if (byte_array == null)
265 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
267 ret = BitConverter.ToInt32(byte_array, 0);
273 /// Returns the value of the requested column as a int64.
275 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
276 public Int64 GetInt64Value(int index)
281 if (index < 0 || index >= _columnTypes.Length)
283 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
286 byte_array = GetValue(index);
287 if (byte_array == null)
289 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
291 ret = BitConverter.ToInt64(byte_array, 0);
297 /// Returns the value of the requested column as a double.
299 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
300 public double GetDoubleValue(int index)
305 if (index < 0 || index >= _columnTypes.Length)
307 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
310 byte_array = GetValue(index);
311 if (byte_array == null)
313 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
315 ret = BitConverter.ToDouble(byte_array, 0);
321 /// Returns the value of the requested column as a string.
323 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
324 public string GetStringValue(int index)
329 if (index < 0 || index >= _columnTypes.Length)
331 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
334 byte_array = GetValue(index);
336 if (byte_array == null)
341 ret = Encoding.UTF8.GetString(byte_array);
347 /// Returns the value of the requested column as a blob.
349 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
350 public byte[] GetBlobValue(int index)
354 if (index < 0 || index >= _columnTypes.Length)
356 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
359 byte_array = GetValue(index);
363 private static class FileManager
365 private static readonly string DATACONTROL_DIRECTORY = "/tmp/";
366 private static Dictionary<int, int> fileTable = new Dictionary<int, int>();
367 public static string OpenFileStream(int threadID)
374 Log.Error(LogTag, "threadID is " + threadID.ToString());
378 if (fileTable.ContainsKey(threadID) == false)
380 fileTable.Add(threadID, 0);
383 index = fileTable[threadID];
385 fileTable[threadID] = index;
387 path = DATACONTROL_DIRECTORY + Application.Current.ApplicationInfo.ApplicationId + "_"+Application.Current.ApplicationInfo.ProcessId.ToString() + "_" + threadID.ToString() + "_" + index.ToString();
394 /// Initializes MatrixCursor class with columnNames and columnTypes.
396 /// <param name="columnNames">MatrixCursor's column name list</param>
397 /// <param name="columnTypes">MatrixCursor's column type list</param>
398 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
399 /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
400 public MatrixCursor(string[] columnNames, ColumnType[] columnTypes)
402 byte[] byte_tmp, length_tmp, string_tmp;
403 int i, total_len_of_column_names = 0;
405 if (columnNames == null || columnTypes == null ||
406 (columnNames.Length != columnTypes.Length) || columnNames.Length < 1)
408 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
411 for (i = 0; i < columnNames.Length; i++)
413 if (string.IsNullOrEmpty(columnNames[i]))
415 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "columnNames index " + i.ToString());
419 for (i = 0; i < columnTypes.Length; i++)
421 if ( columnTypes[i] < ColumnType.ColumnTypeInt || columnTypes[i] > ColumnType.ColumnTypeBlob)
423 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "columnTypes index" + i.ToString());
427 _columnNames = columnNames;
428 _columnTypes = columnTypes;
430 _cursorPath = FileManager.OpenFileStream(Thread.CurrentThread.ManagedThreadId);
431 if (_cursorPath == null)
433 Log.Error(LogTag, "Unable to create a cursor file : " + _cursorPath);
434 ErrorFactory.ThrowException(ResultType.IoError, true);
437 _fs = new FileStream(_cursorPath, FileMode.Create);
439 byte_tmp = BitConverter.GetBytes(columnNames.Length);
440 _fs.Write(byte_tmp, 0, byte_tmp.Length);
443 for (i = 0; i < columnTypes.Length; i++)
445 byte_tmp = BitConverter.GetBytes((int)_columnTypes[i]);
446 _fs.Write(byte_tmp, 0, byte_tmp.Length);
450 for (i = 0; i < columnTypes.Length; i++)
452 string_tmp = Encoding.UTF8.GetBytes(columnNames[i]);
453 byte_tmp = new byte[string_tmp.Length + 1];/*insert null */
455 string_tmp.CopyTo(byte_tmp, 0);
457 length_tmp = BitConverter.GetBytes(byte_tmp.Length);
458 total_len_of_column_names += length_tmp.Length;
460 _fs.Write(length_tmp, 0, length_tmp.Length);
461 _fs.Write(byte_tmp, 0, byte_tmp.Length);
464 /* total length of column names */
465 byte_tmp = BitConverter.GetBytes(total_len_of_column_names);
466 _fs.Write(byte_tmp, 0, byte_tmp.Length);
468 _rowCountPosition = _fs.Position;
470 byte_tmp = BitConverter.GetBytes(_rowCount);
471 _fs.Write(byte_tmp, 0, byte_tmp.Length);
475 internal MatrixCursor()
477 _columnNames = new string[0];
478 _columnTypes = new ColumnType[0];
484 /// Adds a new row to the end with the given column values.
486 /// <param name="columnValues">New column values</param>
487 /// <exception cref="ArgumentException">Thrown in case of Invalid parmaeter.</exception>
488 public void AddRow(object[] columnValues)
491 byte[] type_array, length_array, value_array = null, string_array, byte_tmp;
493 if (columnValues == null || columnValues.Length <= 0 || columnValues.Length != _columnTypes.Length)
495 ErrorFactory.ThrowException(ResultType.InvalidParamer, false);
498 using (MemoryStream ms = new MemoryStream())
500 for (i = 0; i < _columnTypes.Length; i++)
502 type_array = BitConverter.GetBytes((int)_columnTypes[i]);
503 switch (_columnTypes[i])
505 case ColumnType.ColumnTypeInt:
506 if (!(columnValues[i] is Int64) && !(columnValues[i] is Int32))
508 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "Type mismatch :Index " + i.ToString());
511 value_array = BitConverter.GetBytes(Convert.ToUInt64(columnValues[i]));
512 size = value_array.Length;
514 case ColumnType.ColumnTypeDouble:
515 if (!(columnValues[i] is Double))
517 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "Type mismatch :Index " + i.ToString());
520 value_array = BitConverter.GetBytes(Convert.ToDouble(columnValues[i]));
521 size = value_array.Length;
523 case ColumnType.ColumnTypeString:
524 if (columnValues[i] == null)
526 type_array = BitConverter.GetBytes(ColumnTypeNull);
531 if (!(columnValues[i] is string))
533 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "Type mismatch :Index " + i.ToString());
536 string_array = Encoding.UTF8.GetBytes(Convert.ToString(columnValues[i]));
537 value_array = new byte[string_array.Length + 1];/*insert null */
538 string_array.CopyTo(value_array, 0);
539 size = value_array.Length;
542 case ColumnType.ColumnTypeBlob:
543 if (columnValues[i] == null)
545 type_array = BitConverter.GetBytes(ColumnTypeNull);
550 if (!(columnValues[i] is byte[]))
552 ErrorFactory.ThrowException(ResultType.InvalidParamer, false, "Type mismatch :Index " + i.ToString());
555 value_array = (byte[])columnValues[i];
556 size = value_array.Length;
560 ms.Write(type_array, 0, type_array.Length);
562 length_array = BitConverter.GetBytes(size);
563 ms.Write(length_array, 0, length_array.Length);
566 ms.Write(value_array, 0, value_array.Length);
570 /* update row count */
572 byte_tmp = BitConverter.GetBytes(_rowCount);
573 _fs.Seek(_rowCountPosition, SeekOrigin.Begin);
574 _fs.Write(byte_tmp, 0, byte_tmp.Length);
576 _fs.Seek(0, SeekOrigin.End);
578 _rowFieldOffset.Add(_fs.Position);
579 ms.WriteTo(_fs);/* row data */
582 Log.Debug(LogTag, "_fs pos = " + _fs.Position.ToString());
583 Log.Debug(LogTag, "_fs len = " + _fs.Length.ToString());
588 /// Releases all resources used by the MatrixCursor class.
590 public void Dispose()
595 protected virtual void Dispose(bool disposing)
599 if (!string.IsNullOrEmpty(_cursorPath))
601 FileInfo fi = new FileInfo(_cursorPath);
619 GC.SuppressFinalize(this);