Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

xbmcvfs python module #36

Closed
wants to merge 1 commit into from

4 participants

@amet

Hi all,

with the help of jcarroll, davilla and JM I have managed to create the xbmcvfs python module that will address the issue of writing to smb:// drives from addons. this is and issue atm on atv2/ios builds and openelec builds but it will become an issue in future once we move to external python altogether.

If there is anything that needs changing please let me know.
Zeljko

@amet amet added: xbmcvfs.(copy,delete,rename,subHash) and xbmcvfs.File.(read, s…
…ize, close)

Thanks to jcarroll,davilla and jmarshall for a lot of the code here,Montellese for the VS2010 project fixup.

usage:
f = xbmcvfs.File(file)
b = f.read()
s = f.size()
f.close()

success = xbmcvfs.copy(source, destination)
xbmcvfs.delete(file)
success = xbmcvfs.rename(file,newFileName)
hash = xbmcvfs.subHash(file)
3fe954f
@ghost

pydocs on read() has a typo and is wrong,

also this is not quite what i had in mind, in particular it does not implement the stdio interface.
fread(dest,size,nmemb,file) and so on. once this get to be used in all sorts of add-ons through swig, it will often be used for fileio callbacks. then we need this form. i'm not suggesting replacing, but rather have functions with the stdio calling conventions as well.

@topfs2
Collaborator

Something which has an API closer to https://github.com/topfs2/libvfs this I guess. Could perhaps do a wrapper IO hook for our vfs for that lib and use it as a stepping stone of using that lib in core?

@davilla
Collaborator

if the xbmcvfs.File implementation is an issue, then that part can be dropped until such hooks to stdio are needed and written. xbmcvfs.(copy,delete,rename,subHash) are basic file operations and that part of the API will most likely not change over time. In fact, the only function needed with external python right now to is copy.

@taxigps
Collaborator

I have a problem need xbmcvfs.file. In shooter service of script.xbmc.subtitles, need to read some data of video file to calculate special hash for search subtitles. Many people use xbmc on ATV or IPAD, and movies store on smb server. So some api like xbmcvfs.file important for this.

@amet amet referenced this pull request
Merged

xbmcvfs extend #1013

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 15, 2011
  1. @amet

    added: xbmcvfs.(copy,delete,rename,subHash) and xbmcvfs.File.(read, s…

    amet authored
    …ize, close)
    
    Thanks to jcarroll,davilla and jmarshall for a lot of the code here,Montellese for the VS2010 project fixup.
    
    usage:
    f = xbmcvfs.File(file)
    b = f.read()
    s = f.size()
    f.close()
    
    success = xbmcvfs.copy(source, destination)
    xbmcvfs.delete(file)
    success = xbmcvfs.rename(file,newFileName)
    hash = xbmcvfs.subHash(file)
This page is out of date. Refresh to see the latest.
View
4 XBMC.xcodeproj/project.pbxproj
@@ -42,6 +42,7 @@
183FDF8B11AF0B0500B81E9C /* PluginSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 183FDF8811AF0B0500B81E9C /* PluginSource.cpp */; };
184C472F1296BC6E0006DB3E /* Service.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 184C472D1296BC6E0006DB3E /* Service.cpp */; };
184C47301296BC6E0006DB3E /* Service.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 184C472D1296BC6E0006DB3E /* Service.cpp */; };
+ 189047D21301DEAB00C11012 /* xbmcvfsmodule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 189047D11301DEAB00C11012 /* xbmcvfsmodule.cpp */; };
18B4A0021152BFA5001AF8A6 /* Addon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 18B49FF11152BFA5001AF8A6 /* Addon.cpp */; };
18B4A0031152BFA5001AF8A6 /* AddonManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 18B49FF41152BFA5001AF8A6 /* AddonManager.cpp */; };
18B4A0041152BFA5001AF8A6 /* fft.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 18B49FF91152BFA5001AF8A6 /* fft.cpp */; };
@@ -1909,6 +1910,7 @@
183FDF8911AF0B0500B81E9C /* PluginSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginSource.h; sourceTree = "<group>"; };
184C472D1296BC6E0006DB3E /* Service.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Service.cpp; sourceTree = "<group>"; };
184C472E1296BC6E0006DB3E /* Service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Service.h; sourceTree = "<group>"; };
+ 189047D11301DEAB00C11012 /* xbmcvfsmodule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xbmcvfsmodule.cpp; sourceTree = "<group>"; };
18B49FF11152BFA5001AF8A6 /* Addon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Addon.cpp; sourceTree = "<group>"; };
18B49FF21152BFA5001AF8A6 /* Addon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Addon.h; sourceTree = "<group>"; };
18B49FF31152BFA5001AF8A6 /* AddonDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddonDll.h; sourceTree = "<group>"; };
@@ -5993,6 +5995,7 @@
E38E19DA0D25F9FB00618676 /* xbmcmodule */ = {
isa = PBXGroup;
children = (
+ 189047D11301DEAB00C11012 /* xbmcvfsmodule.cpp */,
7CD2CCFE11B38B000009EFC1 /* PythonAddon.cpp */,
7CD2CCFF11B38B000009EFC1 /* PythonAddon.h */,
7CD2CD0011B38B000009EFC1 /* xbmcaddonmodule.cpp */,
@@ -8173,6 +8176,7 @@
433219D812E4C6A500CD7486 /* udf25.cpp in Sources */,
433219D912E4C6A500CD7486 /* UDFDirectory.cpp in Sources */,
7C4705AE12EF584C00369E51 /* AddonInstaller.cpp in Sources */,
+ 189047D21301DEAB00C11012 /* xbmcvfsmodule.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
1  project/VS2010Express/XBMC.vcxproj
@@ -492,6 +492,7 @@
<ClCompile Include="..\..\xbmc\interfaces\python\xbmcmodule\xbmcguimodule.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\xbmcmodule\xbmcmodule.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\xbmcmodule\xbmcplugin.cpp" />
+ <ClCompile Include="..\..\xbmc\interfaces\python\xbmcmodule\xbmcvfsmodule.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\XBPython.cpp" />
<ClCompile Include="..\..\xbmc\interfaces\python\XBPyThread.cpp" />
<ClCompile Include="..\..\xbmc\LangInfo.cpp" />
View
3  project/VS2010Express/XBMC.vcxproj.filters
@@ -2456,6 +2456,9 @@
<ClCompile Include="..\..\xbmc\addons\AddonInstaller.cpp">
<Filter>addons</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\interfaces\python\xbmcmodule\xbmcvfsmodule.cpp">
+ <Filter>interfaces\python\xbmcmodule</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
View
8 xbmc/interfaces/python/XBPython.cpp
@@ -120,6 +120,9 @@ extern "C" {
void InitAddonModule(void);
void InitAddonTypes(void);
void DeinitAddonModule(void);
+ void InitVFSModule(void);
+ void InitVFSTypes(void);
+ void DeinitVFSModule(void);
}
XBPython::XBPython()
@@ -298,7 +301,8 @@ void XBPython::InitializeInterpreter()
InitPluginModule(); // init xbmcplugin modules
InitGUIModule(); // init xbmcgui modules
InitAddonModule(); // init xbmcaddon modules
-
+ InitVFSModule(); // init xbmcvfs modules
+
// redirecting default output to debug console
if (PyRun_SimpleString(""
"import xbmc\n"
@@ -326,6 +330,7 @@ void XBPython::DeInitializeInterpreter()
DeinitPluginModule();
DeinitGUIModule();
DeinitAddonModule();
+ DeinitVFSModule();
}
/**
@@ -408,6 +413,7 @@ void XBPython::Initialize()
InitGUITypes();
InitPluginTypes();
InitAddonTypes();
+ InitVFSTypes();
if (!(m_mainThreadState = PyThreadState_Get()))
CLog::Log(LOGERROR, "Python threadstate is NULL.");
View
1  xbmc/interfaces/python/xbmcmodule/Makefile
@@ -33,6 +33,7 @@ SRCS=action.cpp \
xbmcguimodule.cpp \
xbmcmodule.cpp \
xbmcplugin.cpp \
+ xbmcvfsmodule.cpp \
LIB=xbmcmodule.a
View
413 xbmc/interfaces/python/xbmcmodule/xbmcvfsmodule.cpp
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2005-2011 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#if (defined USE_EXTERNAL_PYTHON)
+ #if (defined HAVE_LIBPYTHON2_6)
+ #include <python2.6/Python.h>
+ #elif (defined HAVE_LIBPYTHON2_5)
+ #include <python2.5/Python.h>
+ #elif (defined HAVE_LIBPYTHON2_4)
+ #include <python2.4/Python.h>
+ #else
+ #error "Could not determine version of Python to use."
+ #endif
+#else
+ #include "python/Include/Python.h"
+#endif
+#include "../XBPythonDll.h"
+
+#include "filesystem/File.h"
+#include "pyutil.h"
+#include "FileUtils.h"
+
+using namespace std;
+using namespace XFILE;
+using namespace PYXBMC;
+
+#ifndef __GNUC__
+#pragma code_seg("PY_TEXT")
+#pragma data_seg("PY_DATA")
+#pragma bss_seg("PY_BSS")
+#pragma const_seg("PY_RDATA")
+#endif
+
+#if defined(__GNUG__) && (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=2)
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace xbmcvfs
+{
+/*****************************************************************
+ * start of xbmcvfs methods
+ *****************************************************************/
+ typedef struct {
+ PyObject_HEAD
+ CFile* pFile;
+ } File;
+
+ PyDoc_STRVAR(file__doc__,
+ "File class.\n"
+ "\n"
+ "example:\n"
+ " f = xbmcvfs.File(file)\n");
+
+ PyObject* File_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ {
+ PyObject *f_line;
+ if (!PyArg_ParseTuple(
+ args,
+ (char*)"O",
+ &f_line))
+ {
+ return NULL;
+ }
+ File *self = (File *)type->tp_alloc(type, 0);
+ if (!self) return NULL;
+ CStdString strSource;
+ if (!PyXBMCGetUnicodeString(strSource, f_line, 1)) return NULL;
+ self->pFile = new CFile();
+ Py_BEGIN_ALLOW_THREADS
+ self->pFile->Open(strSource, READ_NO_CACHE);
+ Py_END_ALLOW_THREADS
+
+ return (PyObject*)self;
+ }
+
+ void File_Dealloc(File* self)
+ {
+ Py_BEGIN_ALLOW_THREADS
+ delete self->pFile;
+ Py_END_ALLOW_THREADS
+
+ self->pFile = NULL;
+ self->ob_type->tp_free((PyObject*)self);
+ }
+
+ // copy() method
+ PyDoc_STRVAR(copy__doc__,
+ "copy(source, destination) -- copy file to destination, returns true/false.\n"
+ "\n"
+ "source : file to copy.\n"
+ "destination : destination file"
+ "\n"
+ "example:\n"
+ " success = xbmcvfs.copy(source, destination)\n");
+
+ PyObject* vfs_copy(PyObject *self, PyObject *args)
+ {
+ PyObject *f_line;
+ PyObject *d_line;
+ if (!PyArg_ParseTuple(
+ args,
+ (char*)"OO",
+ &f_line,
+ &d_line))
+ {
+ return NULL;
+ }
+ CStdString strSource;
+ CStdString strDestnation;
+ bool bResult = true;
+
+ if (!PyXBMCGetUnicodeString(strSource, f_line, 1)) return NULL;
+ if (!PyXBMCGetUnicodeString(strDestnation, d_line, 1)) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ bResult = CFile::Cache(strSource, strDestnation);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue((char*)"b", bResult);
+ }
+ PyDoc_STRVAR(delete__doc__,
+ "delete(file)\n"
+ "\n"
+ "file : file to delete"
+ "\n"
+ "example:\n"
+ " xbmcvfs.delete(file)\n");
+
+ // delete a file
+ PyObject* vfs_delete(File *self, PyObject *args, PyObject *kwds)
+ {
+ PyObject *f_line;
+ if (!PyArg_ParseTuple(
+ args,
+ (char*)"O",
+ &f_line))
+ {
+ return NULL;
+ }
+ CStdString strSource;
+ if (!PyXBMCGetUnicodeString(strSource, f_line, 1)) return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ self->pFile->Delete(strSource);
+ Py_END_ALLOW_THREADS
+
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ }
+
+ PyDoc_STRVAR(rename__doc__,
+ "rename(file, newFileName)\n"
+ "\n"
+ "file : file to reaname"
+ "newFileName : new filename"
+ "\n"
+ "example:\n"
+ " success = xbmcvfs.rename(file,newFileName)\n");
+
+ // rename a file
+ PyObject* vfs_rename(File *self, PyObject *args, PyObject *kwds)
+ {
+ PyObject *f_line;
+ PyObject *d_line;
+ if (!PyArg_ParseTuple(
+ args,
+ (char*)"OO",
+ &f_line,
+ &d_line))
+ {
+ return NULL;
+ }
+ CStdString strSource;
+ CStdString strDestnation;
+ if (!PyXBMCGetUnicodeString(strSource, f_line, 1)) return NULL;
+ if (!PyXBMCGetUnicodeString(strDestnation, d_line, 1)) return NULL;
+
+ bool bResult;
+ Py_BEGIN_ALLOW_THREADS
+ bResult = self->pFile->Rename(strSource,strDestnation);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue((char*)"b", bResult);
+
+ }
+ PyDoc_STRVAR(subHash__doc__,
+ "subHash(file)\n"
+ "\n"
+ "file : file to calculate subtitle hash for"
+ "\n"
+ "example:\n"
+ " hash = xbmcvfs.subHash(file)\n");
+ PyObject* vfs_subHash(File *self, PyObject *args, PyObject *kwds)
+ {
+ PyObject *f_line;
+ if (!PyArg_ParseTuple(
+ args,
+ (char*)"O",
+ &f_line))
+ {
+ return NULL;
+ }
+ CStdString strSource;
+ if (!PyXBMCGetUnicodeString(strSource, f_line, 1)) return NULL;
+
+ CStdString s_buffer;
+ Py_BEGIN_ALLOW_THREADS
+ s_buffer = CFileUtils::SubtitleHash(strSource);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue((char*)"s",s_buffer.c_str());
+ }
+
+ // define c functions to be used in python here
+ PyMethodDef xbmcvfsMethods[] = {
+ {(char*)"copy", (PyCFunction)vfs_copy, METH_VARARGS, copy__doc__},
+ {(char*)"delete", (PyCFunction)vfs_delete, METH_VARARGS, delete__doc__},
+ {(char*)"rename", (PyCFunction)vfs_rename, METH_VARARGS, rename__doc__},
+ {(char*)"subHash", (PyCFunction)vfs_subHash, METH_VARARGS, subHash__doc__},
+ {NULL, NULL, 0, NULL}
+ };
+
+ PyDoc_STRVAR(read__doc__,
+ "read(bytes)\n"
+ "\n"
+ "bytes : now many bytes to read [opt]- if not set it will read the whole file"
+ "\n"
+ "example:\n"
+ " f = xbmcvfs.File(file)\n"
+ " b = f.read()\n"
+ " f.close()\n"
+ );
+
+ // read a file
+ PyObject* File_read(File *self, PyObject *args)
+ {
+ unsigned int readBytes;
+ if (!PyArg_ParseTuple(args, (char*)"|i", &readBytes)) return NULL;
+
+ if (readBytes < 0)
+ {
+ Py_BEGIN_ALLOW_THREADS
+ readBytes = self->pFile->GetLength();
+ Py_END_ALLOW_THREADS
+ }
+
+ char* buffer = new char[readBytes + 1];
+ unsigned int bytesRead;
+ Py_BEGIN_ALLOW_THREADS
+ bytesRead = self->pFile->Read(buffer, readBytes);
+ Py_END_ALLOW_THREADS
+ buffer[(bytesRead <= readBytes ? bytesRead : readBytes) + 1] = 0;
+ PyObject* ret = Py_BuildValue((char*)"s", buffer);
+ delete[] buffer;
+ return ret;
+ }
+
+ PyDoc_STRVAR(size__doc__,
+ "size()\n"
+ "\n"
+ "example:\n"
+ " f = xbmcvfs.File(file)\n"
+ " s = f.size()\n"
+ " f.close()\n"
+ );
+
+ // size of a file
+ PyObject* File_size(File *self, PyObject *args)
+ {
+ int readBytes;
+ Py_BEGIN_ALLOW_THREADS
+ readBytes = self->pFile->GetLength();
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue((char*)"i", readBytes);
+ }
+
+ PyDoc_STRVAR(seek__doc__,
+ "seek()\n"
+ "\n"
+ "FilePosition : possition in the file\n"
+ "Whence : where in a file to seek from[0 begining, 1 current , 2 end possition]\n"
+ "example:\n"
+ " f = xbmcvfs.File(file)\n"
+ " s = f.seek(8129, 0)\n"
+ " f.close()\n"
+ );
+
+ // seek a file
+ PyObject* File_seek(File *self, PyObject *args)
+ {
+ long long readBytes;
+ int iWhence;
+ if (!PyArg_ParseTuple(args, (char*)"Li", &readBytes, &iWhence )) return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ self->pFile->Seek((int64_t)readBytes,iWhence);
+ Py_END_ALLOW_THREADS
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ PyDoc_STRVAR(close__doc__,
+ "close()\n"
+ "\n"
+ "example:\n"
+ " f = xbmcvfs.File(file)\n"
+ " f.close()\n"
+ );
+
+ // close a file
+ PyObject* File_close(File *self, PyObject *args, PyObject *kwds)
+ {
+ Py_BEGIN_ALLOW_THREADS
+ self->pFile->Close();
+ Py_END_ALLOW_THREADS
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+
+
+/*****************************************************************
+ * end of methods and python objects
+ * initxbmc(void);
+ *****************************************************************/
+
+ /*************************************************************
+ * Meta data for the xbmcvfs.File class
+ *************************************************************/
+ PyMethodDef File_methods[] = {
+ {(char*)"read", (PyCFunction)File_read, METH_VARARGS, read__doc__},
+ {(char*)"size", (PyCFunction)File_size, METH_NOARGS, size__doc__},
+ {(char*)"seek", (PyCFunction)File_seek , METH_VARARGS, seek__doc__},
+ {(char*)"close", (PyCFunction)File_close, METH_NOARGS, close__doc__},
+ {NULL, NULL, 0, NULL}
+ };
+
+ PyTypeObject File_Type;
+
+ void initFile_Type()
+ {
+ PyXBMCInitializeTypeObject(&File_Type);
+
+ File_Type.tp_name = (char*)"xbmcvfs.File";
+ File_Type.tp_basicsize = sizeof(File);
+ File_Type.tp_dealloc = (destructor)File_Dealloc;
+ File_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+ File_Type.tp_doc = file__doc__;
+ File_Type.tp_methods = File_methods;
+ File_Type.tp_base = 0;
+ File_Type.tp_new = File_New;
+ }
+
+
+ PyMODINIT_FUNC
+ DeinitVFSModule()
+ {
+ // no need to Py_DECREF our objects (see InitXBMCMVFSModule()) as they were created only
+ // so that they could be added to the module, which steals a reference.
+ }
+
+ PyMODINIT_FUNC
+ InitVFSModule()
+ {
+ // init general xbmc modules
+ PyObject* pXbmcvfsModule;
+
+ Py_INCREF(&File_Type);
+
+ pXbmcvfsModule = Py_InitModule((char*)"xbmcvfs", xbmcvfsMethods);
+ if (pXbmcvfsModule == NULL) return;
+
+ PyModule_AddObject(pXbmcvfsModule, (char*)"File", (PyObject*)&File_Type);
+ }
+
+ PyMODINIT_FUNC
+ InitVFSTypes(bool bInitTypes)
+ {
+ initFile_Type();
+
+ if (PyType_Ready(&File_Type)) return;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
View
27 xbmc/utils/FileUtils.cpp
@@ -72,3 +72,30 @@ bool CFileUtils::RenameFile(const CStdString &strFile)
}
return false;
}
+
+CStdString CFileUtils::SubtitleHash(const CStdString &path)
+{
+ const size_t chksum_block_size = 8192;
+
+ CFile file;
+ size_t i;
+ uint64_t hash = 0;
+ uint64_t buffer1[chksum_block_size*2];
+ // In natural language it calculates: size + 64k chksum of the first and last 64k
+ // (even if they overlap because the file is smaller than 128k).
+ file.Open(path, READ_NO_CACHE); //open file
+ file.Read(buffer1, chksum_block_size*sizeof(uint64_t)); //read first 64k
+ file.Seek(-(int64_t)chksum_block_size*sizeof(uint64_t), SEEK_END); //seek to the end of the file
+ file.Read(&buffer1[chksum_block_size], chksum_block_size*sizeof(uint64_t)); //read last 64k
+
+ for (i=0;i<chksum_block_size*2;i++)
+ hash += buffer1[i];
+
+ hash += file.GetLength(); //add size
+
+ file.Close(); //close file
+ CStdString strHash;
+ strHash.Format("%"PRIx64"", hash);
+ return strHash;
+}
+
View
1  xbmc/utils/FileUtils.h
@@ -6,4 +6,5 @@ class CFileUtils
public:
static bool DeleteItem(const CFileItemPtr &item, bool force=false);
static bool RenameFile(const CStdString &strFile);
+ static CStdString SubtitleHash(const CStdString &path);
};
Something went wrong with that request. Please try again.