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;
22 using System.Diagnostics;
24 namespace Tizen.Applications.DataControl
27 /// Represents the MatrixCursor class for the DataControl provider's matrix cursor.
29 public class MatrixCursor : IDisposable, ICursor
31 private const string LogTag = "Tizen.Applications.DataControl";
32 private FileStream _fs;
33 private bool _disposed = false;
34 private string _cursorPath;
35 private long _rowCount = 0;
36 private long _rowCountPosition = 0;
37 private int _currentRowIndex = 0;
38 private IList<long> _rowFieldOffset = new List<long>();
39 private string[] _columnNames;
40 private ColumnType[] _columnTypes;
41 private const int ColumnTypeNull = 5;
43 private byte[] GetValue(int index)
45 byte[] int_tmp = new byte[sizeof(int)];
52 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
53 if (read_len != int_tmp.Length)
55 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Type " + index.ToString());
58 type = (ColumnType)BitConverter.ToInt32(int_tmp, 0);
60 if (type != _columnTypes[index])
62 if ((int)type == ColumnTypeNull &&
63 (_columnTypes[index] == ColumnType.ColumnTypeBlob || _columnTypes[index] == ColumnType.ColumnTypeString))
65 return null; /* null type */
68 ErrorFactory.ThrowException(ResultType.IoError, true, "Type mismatch " + index.ToString());
71 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
72 if (read_len != int_tmp.Length)
74 ErrorFactory.ThrowException(ResultType.IoError, true, "Column size " + index.ToString());
77 size = BitConverter.ToInt32(int_tmp, 0);
81 ErrorFactory.ThrowException(ResultType.IoError, true, "Invalid data size " + index.ToString());
84 ret_array = new byte[size];
85 read_len = _fs.Read(ret_array, 0, ret_array.Length);
86 if (read_len != ret_array.Length)
88 ErrorFactory.ThrowException(ResultType.IoError, true, "Column value size " + index.ToString());
95 private void MoveToColumn(int ColumnIndex)
98 byte[] int_tmp = new byte[sizeof(int)];
102 seek_len = _fs.Seek(_rowFieldOffset[_currentRowIndex], SeekOrigin.Begin);
103 if (seek_len != _rowFieldOffset[_currentRowIndex])
105 ErrorFactory.ThrowException(ResultType.IoError, true, "Row index " + _currentRowIndex.ToString());
108 for (i = 0; i < ColumnIndex; i++)
110 /* type(int) size(int) value */
111 switch (_columnTypes[i])
113 case ColumnType.ColumnTypeInt:
114 tmp_position = sizeof(int) * 2 + sizeof(Int64);
115 _fs.Seek(tmp_position, SeekOrigin.Current);
117 case ColumnType.ColumnTypeDouble:
118 tmp_position = sizeof(int) * 2 + sizeof(double);
119 _fs.Seek(tmp_position, SeekOrigin.Current);
121 case ColumnType.ColumnTypeString:
122 tmp_position = sizeof(int);
123 _fs.Seek(tmp_position, SeekOrigin.Current);
124 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
125 if (read_len != int_tmp.Length)
127 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Index " + ColumnIndex.ToString());
130 tmp_position = BitConverter.ToInt32(int_tmp, 0);
132 if (tmp_position > 0)
134 _fs.Seek(tmp_position, SeekOrigin.Current);
138 case ColumnType.ColumnTypeBlob:
139 tmp_position = sizeof(int);
140 _fs.Seek(tmp_position, SeekOrigin.Current);
142 read_len = _fs.Read(int_tmp, 0, int_tmp.Length);
143 if (read_len != int_tmp.Length)
145 ErrorFactory.ThrowException(ResultType.IoError, true, "Column Index " + ColumnIndex.ToString());
148 tmp_position = BitConverter.ToInt32(int_tmp, 0);
150 if (tmp_position > 0)
152 _fs.Seek(tmp_position, SeekOrigin.Current);
161 internal FileStream GetFileStream()
167 /// Gets the column count of the MatrixCursor.
169 public int GetColumnCount()
171 return _columnTypes.Length;
175 /// Returns the column type at the given zero-based column index.
177 /// <param name="index">Target column index</param>
178 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
179 public ColumnType GetColumnType(int index)
181 if (index < 0 || index >= _columnTypes.Length)
183 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
186 return _columnTypes[index];
190 /// Returns the column name at the given zero-based column index.
192 /// <param name="index">The target column index.</param>
193 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
194 public string GetColumnName(int index)
196 if (index < 0 || index >= _columnTypes.Length)
198 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
201 return _columnNames[index];
205 /// Gets the MatrixCursor's row count.
207 public long GetRowCount()
213 /// Move the MatrixCursor to the next row.
217 if (_currentRowIndex >= _rowCount - 1)
227 /// Move the MatrixCursor to the previous row.
231 if (_currentRowIndex <= 0)
241 /// Move the MatrixCursor to the first row.
245 _currentRowIndex = 0;
250 /// Returns the value of the requested column as an integer.
252 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
253 public int GetIntValue(int index)
258 if (index < 0 || index >= _columnTypes.Length)
260 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
263 byte_array = GetValue(index);
264 if (byte_array == null)
266 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
268 ret = BitConverter.ToInt32(byte_array, 0);
274 /// Returns the value of the requested column as int64.
276 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
277 public Int64 GetInt64Value(int index)
282 if (index < 0 || index >= _columnTypes.Length)
284 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
287 byte_array = GetValue(index);
288 if (byte_array == null)
290 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
292 ret = BitConverter.ToInt64(byte_array, 0);
298 /// Returns the value of the requested column as a double.
300 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
301 public double GetDoubleValue(int index)
306 if (index < 0 || index >= _columnTypes.Length)
308 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
311 byte_array = GetValue(index);
312 if (byte_array == null)
314 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
316 ret = BitConverter.ToDouble(byte_array, 0);
322 /// Returns the value of the requested column as a string.
324 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
325 public string GetStringValue(int index)
330 if (index < 0 || index >= _columnTypes.Length)
332 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
335 byte_array = GetValue(index);
337 if (byte_array == null)
342 ret = Encoding.UTF8.GetString(byte_array).TrimEnd('\0');
348 /// Returns the value of the requested column as a BLOB.
350 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
351 public byte[] GetBlobValue(int index)
355 if (index < 0 || index >= _columnTypes.Length)
357 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
360 byte_array = GetValue(index);
364 private static class FileManager
366 private static readonly string DATACONTROL_DIRECTORY = "/tmp/";
367 private static Dictionary<int, int> fileTable = new Dictionary<int, int>();
368 public static string OpenFileStream(int threadID)
375 Log.Error(LogTag, "threadID is " + threadID.ToString());
379 if (fileTable.ContainsKey(threadID) == false)
381 fileTable.Add(threadID, 0);
384 index = fileTable[threadID];
386 fileTable[threadID] = index;
388 path = DATACONTROL_DIRECTORY + Application.Current.ApplicationInfo.ApplicationId + "_" + Process.GetCurrentProcess().Id.ToString() + "_" + threadID.ToString() + "_" + index.ToString();
395 /// Initializes the MatrixCursor class with columnNames and columnTypes.
397 /// <param name="columnNames">The MatrixCursor's column name list.</param>
398 /// <param name="columnTypes">The MatrixCursor's column type list.</param>
399 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
400 /// <exception cref="InvalidOperationException">Thrown in case of any internal error.</exception>
401 public MatrixCursor(string[] columnNames, ColumnType[] columnTypes)
403 byte[] byte_tmp, length_tmp, string_tmp;
404 int i, total_len_of_column_names = 0;
406 if (columnNames == null || columnTypes == null ||
407 (columnNames.Length != columnTypes.Length) || columnNames.Length < 1)
409 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
412 for (i = 0; i < columnNames.Length; i++)
414 if (string.IsNullOrEmpty(columnNames[i]))
416 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "columnNames index " + i.ToString());
420 for (i = 0; i < columnTypes.Length; i++)
422 if ( columnTypes[i] < ColumnType.ColumnTypeInt || columnTypes[i] > ColumnType.ColumnTypeBlob)
424 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "columnTypes index" + i.ToString());
428 _columnNames = columnNames;
429 _columnTypes = columnTypes;
431 _cursorPath = FileManager.OpenFileStream(Thread.CurrentThread.ManagedThreadId);
432 if (_cursorPath == null)
434 Log.Error(LogTag, "Unable to create a cursor file : " + _cursorPath);
435 ErrorFactory.ThrowException(ResultType.IoError, true);
438 _fs = new FileStream(_cursorPath, FileMode.Create);
440 byte_tmp = BitConverter.GetBytes(columnNames.Length);
441 _fs.Write(byte_tmp, 0, byte_tmp.Length);
444 for (i = 0; i < columnTypes.Length; i++)
446 byte_tmp = BitConverter.GetBytes((int)_columnTypes[i]);
447 _fs.Write(byte_tmp, 0, byte_tmp.Length);
451 for (i = 0; i < columnTypes.Length; i++)
453 string_tmp = Encoding.UTF8.GetBytes(columnNames[i]);
454 byte_tmp = new byte[string_tmp.Length + 1];/*insert null */
456 string_tmp.CopyTo(byte_tmp, 0);
458 length_tmp = BitConverter.GetBytes(byte_tmp.Length);
459 total_len_of_column_names += length_tmp.Length;
461 _fs.Write(length_tmp, 0, length_tmp.Length);
462 _fs.Write(byte_tmp, 0, byte_tmp.Length);
465 /* total length of column names */
466 byte_tmp = BitConverter.GetBytes(total_len_of_column_names);
467 _fs.Write(byte_tmp, 0, byte_tmp.Length);
469 _rowCountPosition = _fs.Position;
471 byte_tmp = BitConverter.GetBytes(_rowCount);
472 _fs.Write(byte_tmp, 0, byte_tmp.Length);
476 internal MatrixCursor()
478 _columnNames = new string[0];
479 _columnTypes = new ColumnType[0];
485 /// Adds a new row to the end with the given column values.
487 /// <param name="columnValues">New column values</param>
488 /// <exception cref="ArgumentException">Thrown in case of an invalid parameter.</exception>
489 public void AddRow(object[] columnValues)
492 byte[] type_array, length_array, value_array = null, string_array, byte_tmp;
494 if (columnValues == null || columnValues.Length <= 0 || columnValues.Length != _columnTypes.Length)
496 ErrorFactory.ThrowException(ResultType.InvalidParameter, false);
499 using (MemoryStream ms = new MemoryStream())
501 for (i = 0; i < _columnTypes.Length; i++)
503 type_array = BitConverter.GetBytes((int)_columnTypes[i]);
504 switch (_columnTypes[i])
506 case ColumnType.ColumnTypeInt:
507 if (!(columnValues[i] is Int64) && !(columnValues[i] is Int32))
509 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "Type mismatch :Index " + i.ToString());
512 value_array = BitConverter.GetBytes(Convert.ToUInt64(columnValues[i]));
513 size = value_array.Length;
515 case ColumnType.ColumnTypeDouble:
516 if (!(columnValues[i] is Double))
518 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "Type mismatch :Index " + i.ToString());
521 value_array = BitConverter.GetBytes(Convert.ToDouble(columnValues[i]));
522 size = value_array.Length;
524 case ColumnType.ColumnTypeString:
525 if (columnValues[i] == null)
527 type_array = BitConverter.GetBytes(ColumnTypeNull);
532 if (!(columnValues[i] is string))
534 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "Type mismatch :Index " + i.ToString());
537 string_array = Encoding.UTF8.GetBytes(Convert.ToString(columnValues[i]));
538 value_array = new byte[string_array.Length + 1];/*insert null */
539 string_array.CopyTo(value_array, 0);
540 size = value_array.Length;
543 case ColumnType.ColumnTypeBlob:
544 if (columnValues[i] == null)
546 type_array = BitConverter.GetBytes(ColumnTypeNull);
551 if (!(columnValues[i] is byte[]))
553 ErrorFactory.ThrowException(ResultType.InvalidParameter, false, "Type mismatch :Index " + i.ToString());
556 value_array = (byte[])columnValues[i];
557 size = value_array.Length;
561 ms.Write(type_array, 0, type_array.Length);
563 length_array = BitConverter.GetBytes(size);
564 ms.Write(length_array, 0, length_array.Length);
567 ms.Write(value_array, 0, value_array.Length);
571 /* update row count */
573 byte_tmp = BitConverter.GetBytes(_rowCount);
574 _fs.Seek(_rowCountPosition, SeekOrigin.Begin);
575 _fs.Write(byte_tmp, 0, byte_tmp.Length);
577 _fs.Seek(0, SeekOrigin.End);
579 _rowFieldOffset.Add(_fs.Position);
580 ms.WriteTo(_fs);/* row data */
583 Log.Debug(LogTag, "_fs pos = " + _fs.Position.ToString());
584 Log.Debug(LogTag, "_fs len = " + _fs.Length.ToString());
589 /// Releases all the resources used by the MatrixCursor class.
591 public void Dispose()
597 /// Releases the unmanaged resources used by the MatrixCursor class specifying whether to perform a normal dispose operation.
599 /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
600 protected virtual void Dispose(bool disposing)
604 if (!string.IsNullOrEmpty(_cursorPath))
606 FileInfo fi = new FileInfo(_cursorPath);
624 GC.SuppressFinalize(this);
629 /// Destructor of the MatrixCursor class.