diff -Nru ultracopier-1.6.1.3/android-libultracopier.so-deployment-settings.json ultracopier-2.2.4.4/android-libultracopier.so-deployment-settings.json
--- ultracopier-1.6.1.3/android-libultracopier.so-deployment-settings.json 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/android-libultracopier.so-deployment-settings.json 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,14 @@
+{
+ "description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.",
+ "qt": "/usr",
+ "sdk": "",
+ "sdkBuildToolsRevision": "",
+ "ndk": "/opt/android/android-ndk",
+ "toolchain-prefix": "arm-linux-androideabi",
+ "tool-prefix": "arm-linux-androideabi",
+ "toolchain-version": "4.9",
+ "ndk-host": "",
+ "target-architecture": "",
+ "qml-root-path": "/data",
+ "application-binary": "/data/libultracopier.so"
+}
diff -Nru ultracopier-1.6.1.3/android-sources/AndroidManifest.xml ultracopier-2.2.4.4/android-sources/AndroidManifest.xml
--- ultracopier-1.6.1.3/android-sources/AndroidManifest.xml 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/android-sources/AndroidManifest.xml 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru ultracopier-1.6.1.3/android-sources/build.sh ultracopier-2.2.4.4/android-sources/build.sh
--- ultracopier-1.6.1.3/android-sources/build.sh 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/android-sources/build.sh 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,7 @@
+#!/bin/sh
+cd /home/user/src/
+mkdir ~/build && cd ~/build
+qmake -r ~/src/other-pro/ultracopier-little.pro ANDROID_EXTRA_LIBS+=$ANDROID_DEV/lib/libcrypto.so ANDROID_EXTRA_LIBS+=$ANDROID_DEV/lib/libssl.so
+make -j5
+make install INSTALL_ROOT=/home/user/build/dist/
+androiddeployqt --input android-libultracopier.so-deployment-settings.json --output dist/ --android-platform 28 --deployment bundled --gradle --release
Binary files /tmp/tmpeCI20_/eB9BgkOyvV/ultracopier-1.6.1.3/android-sources/res/drawable-hdpi/icon.png and /tmp/tmpeCI20_/iwZncUU5FX/ultracopier-2.2.4.4/android-sources/res/drawable-hdpi/icon.png differ
Binary files /tmp/tmpeCI20_/eB9BgkOyvV/ultracopier-1.6.1.3/android-sources/res/drawable-ldpi/icon.png and /tmp/tmpeCI20_/iwZncUU5FX/ultracopier-2.2.4.4/android-sources/res/drawable-ldpi/icon.png differ
Binary files /tmp/tmpeCI20_/eB9BgkOyvV/ultracopier-1.6.1.3/android-sources/res/drawable-mdpi/icon.png and /tmp/tmpeCI20_/iwZncUU5FX/ultracopier-2.2.4.4/android-sources/res/drawable-mdpi/icon.png differ
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,115 @@
+// Implementation of DLL Exports.
+#include "resource.h"
+#include "DDShellExt.h"
+#include "ClassFactory.h"
+#include "Reg.h"
+
+#ifndef _M_X64
+const CLSID CLSID_DDShellExt = {0x68D44A27,0xFFB6,0x4B89,{0xA3,0xE5,0x7B,0x0E,0x50,0xA7,0xAB,0x33}};
+#else
+const CLSID CLSID_DDShellExt = {0x68ff37c4,0x51bc,0x4c2a,{0xa9,0x92,0x7e,0x39,0xbc,0xe,0x70,0x6f}};
+#endif
+
+HINSTANCE g_hInst = NULL;
+long g_cDllRef = 0;
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ (void)lpReserved;
+ switch(dwReason){
+ case DLL_PROCESS_ATTACH:
+ //MessageBox ( NULL,L"DLL_PROCESS_ATTACH", L"DLL_PROCESS_ATTACH", MB_OK);
+ // Hold the instance of this DLL module, we will use it to get the
+ // path of the DLL to register the component.
+ g_hInst = hInstance;
+ DisableThreadLibraryCalls(hInstance);
+ break;
+ case DLL_PROCESS_DETACH:
+ //MessageBox ( NULL,L"DLL_PROCESS_DETACH", L"DLL_PROCESS_DETACH", MB_OK);
+ break;
+ }
+
+ return TRUE; //_AtlModule.DllMain(hInstance, dwReason, lpReserved,ObjectMap,NULL);
+}
+
+
+// Used to determine whether the DLL can be unloaded by OLE
+STDAPI DllCanUnloadNow(void)
+{
+ return g_cDllRef > 0 ? S_FALSE : S_OK;
+}
+
+
+// Returns a class factory to create an object of the requested type
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+{
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+ if (IsEqualCLSID(CLSID_DDShellExt, rclsid))
+ {
+ hr = E_OUTOFMEMORY;
+ ClassFactory *pClassFactory = new ClassFactory();
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ }
+ return hr;
+}
+
+
+// DllRegisterServer - Adds entries to the system registry
+STDAPI DllRegisterServer(void)
+{
+// registers object, typelib and all interfaces in typelib
+
+ HRESULT hr;
+
+ wchar_t szModule[MAX_PATH];
+ if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+ }
+ // Register the component.
+ hr = RegisterInprocServer(szModule, CLSID_DDShellExt, L"CatchCopy Class", L"Apartment");
+ if (SUCCEEDED(hr))
+ {
+ // Register the context menu handler. The context menu handler is
+ // associated with the * file class.
+ hr = RegisterShellExtContextMenuHandler(L"textfile", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Drive", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Directory", CLSID_DDShellExt, L"CatchCopy");
+ hr = RegisterShellExtContextMenuHandler(L"Folder", CLSID_DDShellExt, L"CatchCopy");
+ }
+ return hr;
+}
+
+
+// DllUnregisterServer - Removes entries from the system registry
+STDAPI DllUnregisterServer(void)
+{
+ m_ac.disconnectFromServer();
+ HRESULT hr = S_OK;
+
+ wchar_t szModule[MAX_PATH];
+ if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+ }
+
+ // Unregister the component.
+ hr = UnregisterInprocServer(CLSID_DDShellExt);
+ if (SUCCEEDED(hr))
+ {
+ // Unregister the context menu handler.
+ hr = UnregisterShellExtContextMenuHandler(L"textfile", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Drive", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Directory", CLSID_DDShellExt);
+ hr = UnregisterShellExtContextMenuHandler(L"Folder", CLSID_DDShellExt);
+ return hr;
+ }
+ return S_OK;
+}
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.def ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.def
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.def 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.def 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,7 @@
+LIBRARY "CatchCopy.DLL"
+
+EXPORTS
+ DllGetClassObject = DllGetClassObject@12
+ DllCanUnloadNow = DllCanUnloadNow@0
+ DllRegisterServer = DllRegisterServer@0
+ DllUnregisterServer = DllUnregisterServer@0
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.pro ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.pro
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/CatchCopy.pro 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/CatchCopy.pro 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,49 @@
+QT -= core gui
+
+CONFIG += 64bit
+CONFIG -= exceptions rtti
+
+#DEFINES += CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+
+CONFIG(32bit) {
+ TARGET = catchcopy32
+ QMAKE_CFLAGS = -march=i586 -m32
+ QMAKE_CXXFLAGS = -march=i586 -m32
+ QMAKE_LFLAGS += -m32
+}
+CONFIG(64bit) {
+ TARGET = catchcopy64
+ LIBS += -LC:\x86_64-4.9.3-release-win32-seh-rt_v4-rev1\mingw64\lib64
+ DEFINES += _M_X64
+ QMAKE_CFLAGS = -m64
+ QMAKE_CXXFLAGS = -m64
+ QMAKE_LFLAGS += -m64
+}
+
+QMAKE_CFLAGS -= -fexceptions -mthreads -O2
+QMAKE_CXXFLAGS -= -fexceptions -mthreads -O2
+QMAKE_CFLAGS += -std=c++98 -fno-keep-inline-dllexport -mtune=generic -fno-exceptions -Os -Wall -Wextra -fno-rtti -s -static -static-libgcc -static-libstdc++
+QMAKE_CXXFLAGS += -std=c++98 -fno-keep-inline-dllexport -mtune=generic -fno-exceptions -Os -Wall -Wno-write-strings -Wextra -fno-rtti -s -static -static-libgcc -static-libstdc++
+
+DEF_FILE += CatchCopy.def
+
+LIBS+= -lws2_32 -lole32 -luuid -static-libstdc++ -static-libgcc -static
+
+TEMPLATE = lib
+
+HEADERS += \
+ Variable.h \
+ Deque.h \
+ resource.h \
+ Reg.h \
+ ClientCatchcopy.h \
+ DDShellExt.h \
+ ClassFactory.h
+
+SOURCES += \
+ Deque.cpp \
+ ClientCatchcopy.cpp \
+ Reg.cpp \
+ DDShellExt.cpp \
+ ClassFactory.cpp \
+ CatchCopy.cpp
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClassFactory.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClassFactory.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClassFactory.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClassFactory.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,84 @@
+
+#include "ClassFactory.h"
+#include "DDShellExt.h"
+#include
+#include
+
+extern long g_cDllRef;
+
+ClassFactory::ClassFactory() : m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+ClassFactory::~ClassFactory()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+// IUnknown
+HRESULT __stdcall ClassFactory::QueryInterface(const IID& iid, void **ppv)
+{
+ if(iid == IID_IUnknown || iid == IID_IClassFactory)
+ {
+ *ppv = static_cast(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ reinterpret_cast(*ppv)->AddRef();
+ return S_OK;
+}
+ULONG __stdcall ClassFactory::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+ULONG __stdcall ClassFactory::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ {
+ delete this;
+ }
+ return cRef;
+}
+
+//CreateInstance
+HRESULT __stdcall ClassFactory::CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv)
+{
+ HRESULT hr = CLASS_E_NOAGGREGATION;
+
+ // pIUnknownOuter is used for aggregation. We do not support it in the sample.
+ if (pIUnknownOuter == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+
+ //// Create the COM component.
+ CDDShellExt *pExt = new (std::nothrow) CDDShellExt();
+ if (pExt)
+ {
+ // Query the specified interface.
+ hr = pExt->QueryInterface(iid, ppv);
+ pExt->Release();
+ }
+ }
+
+ return hr;
+}
+
+HRESULT __stdcall ClassFactory::LockServer(BOOL bLock)
+{
+ if(bLock == TRUE)
+ {
+ InterlockedIncrement(&g_cDllRef);
+ }
+ else
+ {
+ InterlockedDecrement(&g_cDllRef);
+ }
+ return S_OK;
+}
+
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClassFactory.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClassFactory.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClassFactory.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClassFactory.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,22 @@
+#pragma once
+
+#include // For IClassFactory
+#include
+
+
+class ClassFactory : public IClassFactory
+{
+public:
+ //interface iunknown
+ virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
+ virtual ULONG __stdcall AddRef();
+ virtual ULONG __stdcall Release();
+ //interface iclassfactory
+ virtual HRESULT __stdcall CreateInstance(IUnknown *pIUnknownOuter, const IID& iid, void **ppv);
+ virtual HRESULT __stdcall LockServer(BOOL bLock);
+
+ ClassFactory();
+ ~ClassFactory();
+private:
+ long m_cRef;
+};
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClientCatchcopy.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,455 @@
+/** \file ClientCatchcopy.cpp
+\brief Define the catchcopy client
+\author alpha_one_x86
+\version 0002
+\date 2010 */
+
+#include
+
+#include "ClientCatchcopy.h"
+#include
+//#pragma comment(lib, "Ws2_32.lib")
+
+#undef NONBLOCK_FLAG
+ClientCatchcopy::ClientCatchcopy()
+{
+ m_hpipe=NULL;
+ idNextOrder=0;
+ const char prefix[]="\\\\.\\pipe\\advanced-copier-";
+ char uname[1024];
+ DWORD len=1023;
+ char *data;
+ // false ??
+ if(GetUserNameA(uname, &len)!=FALSE)
+ {
+ // convert into hexa
+ data = toHex(uname);
+ m_pipename = (char *) malloc(sizeof(prefix)+strlen(data)+2);
+ #if defined(_MFC_VER)
+ strcpy_s(m_pipename, _countof(prefix) ,prefix);
+ strcat_s(m_pipename, sizeof(prefix)+strlen(data)+2,data);
+ #else
+ strcpy(m_pipename, prefix);
+ strcat(m_pipename, data);
+ #endif
+ free(data);
+ m_blk=NULL;
+ m_len=0;
+ m_tot=0;
+
+ canConnect=true;
+ }
+ else
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"GetUserName Failed", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ canConnect=false;
+ }
+}
+
+ClientCatchcopy::~ClientCatchcopy()
+{
+ disconnectFromServer();
+}
+
+// Dump UTF16 (little endian)
+char * ClientCatchcopy::toHex(const char *str)
+{
+ char *p, *sz;
+ size_t len;
+ if (str==NULL)
+ return NULL;
+ len= strlen(str);
+ p = sz = (char *) malloc((len+1)*4);
+ // username goes hexa...
+ for (size_t i=0; iBUFFER_PIPE) ? BUFFER_PIPE:m_len;
+ #ifdef NONBLOCK_FLAG
+ writePipe_nonBlock(m_hpipe, ptr, max);
+ break;
+ #else
+ if(writePipe(m_hpipe, ptr, max)!=0)
+ {
+ ret=-2;
+ break;
+ }
+ m_len-=max;
+ ptr+=max;
+ #endif
+ }
+ }
+ return ret;
+}
+
+int ClientCatchcopy::writePipe(HANDLE hPipe, byte_t *ptr, int len)
+{
+ DWORD cbWritten;
+ if (!WriteFile(hPipe, ptr, len, &cbWritten, NULL))
+ return -4;
+ return 0;
+}
+
+#ifdef NONBLOCK_FLAG
+int ClientCatchcopy::writePipe_nonBlock(HANDLE hPipe, byte_t *ptr, int len)
+{
+ DWORD cbWritten;
+ WriteFile(hPipe, ptr, len, &cbWritten, NULL);
+ return 0;
+}
+#endif
+
+// Add int32 (big-endian) into binary block
+int ClientCatchcopy::addInt32(int value)
+{
+ blkGrowing(sizeof(int));
+ // add value
+ setInt32(m_len, value);
+ m_len+=sizeof(int);
+ return m_len-sizeof(int);
+}
+
+void ClientCatchcopy::setInt32(int offset, int value)
+{
+ C_INT(m_blk+offset)=htonl(value);
+}
+
+// Add unicode string into binary block from ASCIIZ
+int ClientCatchcopy::addStr(WCHAR *data)
+{
+ int ret=-1, len;
+ WCHAR *x;
+ if (data!=NULL && *data)
+ {
+ // le => be
+ x = _wcsdup(data);
+ len = toBigEndian(x);
+ // set size of string
+ ret = addInt32(len);
+ // and add it to block
+ blkGrowing(len);
+ memmove(m_blk+m_len, x, len);
+ m_len+=len;
+ free(x);
+ }
+ return ret;
+}
+
+// resize binary block (if needed)
+byte_t *ClientCatchcopy::blkGrowing(int added)
+{
+ if (m_len+added>m_tot)
+ {
+ // check if added isn't bigger than buffer itself...
+ m_tot+= (added>BLOCK_SIZ) ? added:BLOCK_SIZ;
+ m_blk = (byte_t *) realloc(m_blk, m_tot);
+ }
+ return m_blk+m_len;
+}
+
+int ClientCatchcopy::toBigEndian(WCHAR *p)
+{
+ WCHAR tmp;
+ int ret=0;
+ while(*p)
+ {
+ tmp = htons(*p);
+ *p++=tmp;
+ ret+=2;
+ }
+ return ret;
+}
+
+void ClientCatchcopy::clear()
+{
+ m_tot=0;
+ m_len=0;
+ idNextOrder=0;
+ if (m_blk!=NULL)
+ {
+ free(m_blk);
+ m_blk=NULL;
+ }
+}
+
+bool ClientCatchcopy::isConnected()
+{
+ if(m_hpipe==NULL)
+ return false;
+
+ bool fSuccess = PeekNamedPipe(
+ m_hpipe,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+
+ if(!fSuccess && GetLastError() != ERROR_MORE_DATA)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ void* lpBuffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ ::GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpBuffer,
+ 0,
+ NULL );
+ MessageBox(NULL,(LPCTSTR)lpBuffer, L"Error detected with the connexion", MB_OK);
+ LocalFree( lpBuffer );
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ disconnectFromServer();
+ return false;
+ }
+ else
+ return true;
+}
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClientCatchcopy.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClientCatchcopy.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/ClientCatchcopy.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/ClientCatchcopy.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,68 @@
+/** \file ClientCatchcopy.h
+\brief Define the catchcopy client
+\author alpha_one_x86
+\version 0002
+\date 2010 */
+
+#ifndef CLIENTCATCHCOPY_H
+#define CLIENTCATCHCOPY_H
+
+#define NONBLOCK_FLAG
+#define BUFSIZE 512
+#define S_LEN 8
+
+#define C_INT(p) *((int *) (p))
+#define BLOCK_SIZ 64000
+#define BUFFER_PIPE 32000
+
+#include
+#include
+#include
+#include
+
+#include "Variable.h"
+#include "Deque.h"
+
+typedef unsigned char byte_t;
+
+class ClientCatchcopy
+{
+ public:
+ ClientCatchcopy();
+ ~ClientCatchcopy();
+ bool connectToServer();
+ void disconnectFromServer();
+ /// \brief to send order
+ bool sendProtocol();
+ bool setClientName(wchar_t *name);
+ bool addCopyWithDestination(CDeque sources,wchar_t *destination);
+ bool addCopyWithoutDestination(CDeque sources);
+ bool addMoveWithDestination(CDeque sources,wchar_t *destination);
+ bool addMoveWithoutDestination(CDeque sources);
+ /// \brief to send stream of string list
+ bool sendRawOrderList(CDeque order,bool first_try=true);
+ bool isConnected();
+ private:
+ HANDLE m_hpipe;
+ unsigned int idNextOrder;
+ char *m_pipename;
+ byte_t *m_blk;
+ int m_tot;
+ int m_len;
+
+ char * toHex(const char *str);
+ int dataToPipe();
+ int addInt32(int value);
+ int addStr(WCHAR *data);
+ byte_t *blkGrowing(int added);
+ void setInt32(int offset, int value);
+ int toBigEndian(WCHAR *p);
+ void clear();
+ int writePipe(HANDLE hPipe, byte_t *ptr, int len);
+ #ifdef NONBLOCK_FLAG
+ int writePipe_nonBlock(HANDLE hPipe, byte_t *ptr, int len);
+ #endif
+ bool canConnect;
+};
+
+#endif // CLIENTCATCHCOPY_H
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/DDShellExt.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/DDShellExt.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/DDShellExt.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/DDShellExt.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,188 @@
+// DDShellExt.cpp : Implementation of CDDShellExt
+
+#include "tchar.h"
+#include "DDShellExt.h"
+#include "ClientCatchcopy.h"
+
+#include
+
+extern HINSTANCE g_hInst;
+extern long g_cDllRef;
+
+CDDShellExt::CDDShellExt(): m_cRef(1)
+{
+ InterlockedIncrement(&g_cDllRef);
+}
+
+CDDShellExt::~CDDShellExt()
+{
+ InterlockedDecrement(&g_cDllRef);
+}
+
+// Query to the interface the component supported.
+IFACEMETHODIMP CDDShellExt::QueryInterface(REFIID riid, void **ppv)
+{
+ if(riid == IID_IUnknown || riid == IID_IContextMenu)
+ {
+ *ppv = static_cast(this);
+ }
+ else if (riid == IID_IShellExtInit)
+ {
+ *ppv = static_cast(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+ reinterpret_cast(*ppv)->AddRef();
+ return S_OK;
+}
+
+// Increase the reference count for an interface on an object.
+IFACEMETHODIMP_(ULONG) CDDShellExt::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+// Decrease the reference count for an interface on an object.
+IFACEMETHODIMP_(ULONG) CDDShellExt::Release()
+{
+ ULONG cRef = InterlockedDecrement(&m_cRef);
+ if (0 == cRef)
+ delete this;
+ return cRef;
+}
+
+STDMETHODIMP CDDShellExt::Initialize(LPCITEMIDLIST pidlFolder,LPDATAOBJECT pDO,HKEY hProgID)
+{
+ (void)hProgID;
+ if(!connected)
+ {
+ bool b = m_ac.connectToServer();
+
+ if (b==true)
+ {
+ connected=true;
+ }
+ else
+ return E_FAIL;
+ }
+
+ FORMATETC fmt={CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
+ STGMEDIUM stg={TYMED_HGLOBAL};
+ HDROP hDrop;
+
+ fDestDir[0]=0;
+ if (!SHGetPathFromIDList(pidlFolder,fDestDir))
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_FAIL 1",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_FAIL;
+ }
+
+ // Detect if it's explorer that started the operation by enumerating available
+ // clipboard formats and searching for one that only explorer uses
+ IEnumFORMATETC *en;
+ FORMATETC fmt2;
+ WCHAR fmtName[65535]=L"\0";
+ fFromExplorer=false;
+ pDO->EnumFormatEtc(DATADIR_GET,&en);
+ while(en->Next(1,&fmt2,NULL)==S_OK){
+ GetClipboardFormatName(fmt2.cfFormat,fmtName,sizeof(fmtName));
+ if (!wcscmp(fmtName,CFSTR_SHELLIDLIST)) fFromExplorer=true;
+ }
+ en->Release();
+
+ // Look for CF_HDROP data in the data object. If there
+ // is no such data, return an error back to Explorer.
+ if (FAILED(pDO->GetData(&fmt,&stg)))
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_INVALIDARG 2",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_INVALIDARG;
+ }
+
+ // Get a pointer to the actual data.
+ hDrop=(HDROP)GlobalLock(stg.hGlobal);
+
+ // Make sure it worked.
+ if (hDrop==NULL)
+ {
+ #ifdef CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ MessageBox(NULL,L"Initialize",L"E_INVALIDARG 1",MB_OK);
+ #endif // CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+ return E_INVALIDARG;
+ }
+
+ UINT numFiles,i;
+ WCHAR fn[MAX_PATH]=L"";
+
+ numFiles=DragQueryFile(hDrop,0xFFFFFFFF,NULL,0);
+
+ if (numFiles)
+ {
+ for(i=0;ilpVerb))
+ return E_INVALIDARG;
+ switch(LOWORD(pInfo->lpVerb))
+ {
+ case 0:// copy
+ if(!m_ac.addCopyWithDestination(sources,fDestDir))
+ return E_FAIL;
+ break;
+ case 1:// move
+ if(!m_ac.addMoveWithDestination(sources,fDestDir))
+ return E_FAIL;
+ break;
+ default :
+ return S_OK;
+ }
+ return S_OK;
+}
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/DDShellExt.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/DDShellExt.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/DDShellExt.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/DDShellExt.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,46 @@
+// DDShellExt.h : Declaration of the CDDShellExt
+
+#pragma once
+#include "resource.h" // main symbols
+#include "shlobj.h"
+#include "ClientCatchcopy.h"
+#include "Variable.h"
+#include "Deque.h"
+
+static bool connected=false;
+static ClientCatchcopy m_ac;
+
+// CDDShellExt
+
+extern const CLSID CLSID_DDShellExt;
+
+class CDDShellExt :
+ public IShellExtInit,
+ public IContextMenu
+{
+private:
+ static int fBaselistHandle;
+ bool fFromExplorer;
+ WCHAR fDestDir[MAX_PATH];
+ //static ClientCatchcopy m_ac;
+ CDeque sources;
+ //static bool connected;
+
+ // Reference count of component.
+ long m_cRef;
+public:
+ // IUnknown
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
+ IFACEMETHODIMP_(ULONG) AddRef();
+ IFACEMETHODIMP_(ULONG) Release();
+
+ // IShellExtInit
+ STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);
+
+ CDDShellExt(void);
+ ~CDDShellExt(void);
+ // IContextMenu
+ STDMETHODIMP GetCommandString(UINT_PTR idCmd,UINT uFlags,UINT* pwReserved,LPSTR pszName,UINT cchMax){(void)idCmd;(void)uFlags;(void)pwReserved;(void)pszName;(void)cchMax;(void)connected;return E_NOTIMPL;};
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO);
+ STDMETHODIMP QueryContextMenu(HMENU,UINT,UINT,UINT,UINT);
+};
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Deque.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Deque.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Deque.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Deque.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,100 @@
+#include "Deque.h"
+#include
+
+CDeque::CDeque(void)
+{
+ top1=0;
+ top2=0;
+ head=NULL;
+ tail=NULL;
+}
+
+CDeque::~CDeque(void)
+{
+}
+
+void CDeque::push_front(wchar_t *str)
+{
+ CNode *temp;
+ if(top1+top2 >= MAX_DEQUE)
+ {
+ return ;
+ }
+
+ if(top1+top2 == 0)
+ {
+ head = new CNode;
+ wcscpy(head->str, str);
+ head->next=NULL;
+ head->prev=NULL;
+ tail=head;
+ top1++;
+ }
+ else
+ {
+ top1++;
+ temp=new CNode;
+ wcscpy(temp->str, str);
+ temp->next=head;
+ temp->prev=NULL;
+ head->prev=temp;
+ head=temp;
+ }
+}
+
+void CDeque::push_back(wchar_t *str)
+{
+ CNode *temp;
+ if(top1+top2 >= MAX_DEQUE)
+ {
+ return ;
+ }
+ if(top1+top2 == 0)
+ {
+ head = new CNode;
+ wcscpy(head->str, str);
+ head->next=NULL;
+ head->prev=NULL;
+ tail=head;
+ top1++;
+ }
+ else
+ {
+ top2++;
+ temp=new CNode;
+ wcscpy(temp->str, str);
+ temp->next=NULL;
+ temp->prev=tail;
+ tail->next=temp;
+ tail=temp;
+ }
+}
+
+int CDeque::size()
+{
+ return top1 + top2;
+}
+
+wchar_t *CDeque::at(int pos)
+{
+ int i=0;
+ CNode *temp;
+
+ if(top1+top2 <= 0)
+ {
+ return NULL;
+ }
+
+ temp=head;
+ while(temp!=NULL)
+ {
+ if(i==pos)
+ return temp->str;
+
+ temp=temp->next;
+
+ i++;
+ }
+
+ return NULL;
+}
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Deque.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Deque.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Deque.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Deque.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,29 @@
+#pragma once
+
+#define MAX_STR_LEN 512
+#define MAX_DEQUE 512
+
+class CNode
+{
+public:
+ wchar_t str[MAX_STR_LEN];
+ class CNode *next;
+ class CNode *prev;
+};
+
+class CDeque : public CNode
+{
+public:
+ CDeque(void);
+ ~CDeque(void);
+
+private:
+ CNode *head,*tail;
+ int top1,top2;
+
+public:
+ void push_front(wchar_t *str);
+ void push_back(wchar_t *str);
+ int size();
+ wchar_t *at(int pos);
+};
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Reg.cpp ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Reg.cpp
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Reg.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Reg.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,403 @@
+#include "Reg.h"
+#include
+
+//
+// FUNCTION: SetHKCRRegistryKeyAndValue
+//
+// PURPOSE: The function creates a HKCR registry key and sets the specified
+// registry value.
+//
+// PARAMETERS:
+// * pszSubKey - specifies the registry key under HKCR. If the key does not
+// exist, the function will create the registry key.
+// * pszValueName - specifies the registry value to be set. If pszValueName
+// is NULL, the function will set the default value.
+// * pszData - specifies the string data of the registry value.
+//
+// RETURN VALUE:
+// If the function succeeds, it returns S_OK. Otherwise, it returns an
+// HRESULT error code.
+//
+HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName,
+ PCWSTR pszData)
+{
+ HRESULT hr;
+ HKEY hKey = NULL;
+
+ // Creates the specified registry key. If the key already exists, the
+ // function opens it.
+ hr = HRESULT_FROM_WIN32(RegCreateKeyEx(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , pszSubKey, 0,
+ NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKey, NULL));
+
+ if (SUCCEEDED(hr))
+ {
+ if (pszData != NULL)
+ {
+ // Set the specified value of the key.
+ DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
+ hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
+ REG_SZ, reinterpret_cast(pszData), cbData));
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ return hr;
+}
+
+LONG RecursiveDeleteKey(HKEY hKeyParent, PCWSTR szKeyChild)
+{
+ // Open the child.
+ HKEY hKeyChild ;
+ LONG lRes = RegOpenKeyEx(hKeyParent, szKeyChild, 0,
+ KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKeyChild) ;
+ if (lRes != ERROR_SUCCESS)
+ {
+ return lRes ;
+ }
+ // Enumerate all of the decendents of this child.
+ FILETIME time ;
+ wchar_t szBuffer[MAX_PATH];
+ DWORD dwSize = MAX_PATH ;
+ while (RegEnumKeyEx(hKeyChild, 0, (LPWSTR)szBuffer, &dwSize, NULL,
+ NULL, NULL, &time) == ERROR_SUCCESS)
+ {
+ // Delete the decendents of this child.
+ lRes = RecursiveDeleteKey(hKeyChild, (PCWSTR)szBuffer) ;
+ if (lRes != ERROR_SUCCESS)
+ {
+ // Cleanup before exiting.
+ RegCloseKey(hKeyChild) ;
+ return lRes;
+ }
+ dwSize = MAX_PATH ;
+ }
+
+ // Close the child.
+ RegCloseKey(hKeyChild) ;
+
+ // Delete this child.
+ return RegDeleteKey(hKeyParent, szKeyChild) ;
+}
+
+//
+// FUNCTION: GetHKCRRegistryKeyAndValue
+//
+// PURPOSE: The function opens a HKCR registry key and gets the data for the
+// specified registry value name.
+//
+// PARAMETERS:
+// * pszSubKey - specifies the registry key under HKCR. If the key does not
+// exist, the function returns an error.
+// * pszValueName - specifies the registry value to be retrieved. If
+// pszValueName is NULL, the function will get the default value.
+// * pszData - a pointer to a buffer that receives the value's string data.
+// * cbData - specifies the size of the buffer in bytes.
+//
+// RETURN VALUE:
+// If the function succeeds, it returns S_OK. Otherwise, it returns an
+// HRESULT error code. For example, if the specified registry key does not
+// exist or the data for the specified value name was not set, the function
+// returns COR_E_FILENOTFOUND (0x80070002).
+//
+HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName,
+ PWSTR pszData, DWORD cbData)
+{
+ HRESULT hr;
+ HKEY hKey = NULL;
+
+ // Try to open the specified registry key.
+ hr = HRESULT_FROM_WIN32(RegOpenKeyEx(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , pszSubKey, 0,
+ KEY_READ, &hKey));
+
+ if (SUCCEEDED(hr))
+ {
+ // Get the data for the specified value name.
+ hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
+ NULL, reinterpret_cast(pszData), &cbData));
+
+ RegCloseKey(hKey);
+ }
+
+ return hr;
+}
+
+//
+// FUNCTION: RegisterInprocServer
+//
+// PURPOSE: Register the in-process component in the registry.
+//
+// PARAMETERS:
+// * pszModule - Path of the module that contains the component
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+// * pszThreadModel - Threading model
+//
+// NOTE: The function creates the HKCR\CLSID\{} key in the registry.
+//
+// HKCR
+// {
+// NoRemove CLSID
+// {
+// ForceRemove {} = s ''
+// {
+// InprocServer32 = s '%MODULE%'
+// {
+// val ThreadingModel = s ''
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
+{
+ if (pszModule == NULL || pszThreadModel == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // Create the HKCR\CLSID\{} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s"
+ #else
+ L"Software\\Classes\\CLSID\\%s"
+ #endif
+ , szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
+
+ // Create the HKCR\CLSID\{}\InprocServer32 key.
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s\\InprocServer32"
+ #else
+ L"Software\\Classes\\CLSID\\%s\\InprocServer32"
+ #endif
+ , szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ // Set the default value of the InprocServer32 key to the
+ // path of the COM module.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
+ if (SUCCEEDED(hr))
+ {
+ // Set the threading model of the component.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, L"ThreadingModel", pszThreadModel);
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+
+//
+// FUNCTION: UnregisterInprocServer
+//
+// PURPOSE: Unegister the in-process component in the registry.
+//
+// PARAMETERS:
+// * clsid - Class ID of the component
+//
+// NOTE: The function deletes the HKCR\CLSID\{} key in the registry.
+//
+HRESULT UnregisterInprocServer(const CLSID& clsid)
+{
+ HRESULT hr = S_OK;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // Delete the HKCR\CLSID\{} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"CLSID\\%s"
+ #else
+ L"Software\\Classes\\CLSID\\%s"
+ #endif
+ , szCLSID);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = HRESULT_FROM_WIN32(RecursiveDeleteKey(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , szSubkey));
+ }
+
+ return hr;
+}
+//
+// FUNCTION: RegisterShellExtContextMenuHandler
+//
+// PURPOSE: Register the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+//
+// NOTE: The function creates the following key in the registry.
+//
+// HKCR
+// {
+// NoRemove
+// {
+// NoRemove shellex
+// {
+// NoRemove ContextMenuHandlers
+// {
+// {} = s ''
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
+{
+ if (pszFileType == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // If pszFileType starts with '.', try to read the default value of the
+ // HKCR\ key which contains the ProgID to which the file type
+ // is linked.
+ if (*pszFileType == L'.')
+ {
+ wchar_t szDefaultVal[260];
+ hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
+ sizeof(szDefaultVal));
+
+ // If the key exists and its default value is not empty, use the
+ // ProgID as the file type.
+ if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
+ {
+ pszFileType = szDefaultVal;
+ }
+ }
+
+ // Create the key HKCR\\shellex\DragDropHandlers\{}
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"%s\\shellex\\DragDropHandlers\\%s"
+ #else
+ L"Software\\Classes\\%s\\shellex\\DragDropHandlers\\%s"
+ #endif
+ , pszFileType, szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ // Set the default value of the key.
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
+ }
+
+ return hr;
+}
+
+
+//
+// FUNCTION: UnregisterShellExtContextMenuHandler
+//
+// PURPOSE: Unregister the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+//
+// NOTE: The function removes the {} key under
+// HKCR\\shellex\ContextMenuHandlers in the registry.
+//
+HRESULT UnregisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid)
+{
+ if (pszFileType == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr;
+
+ wchar_t szCLSID[MAX_PATH];
+ StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
+
+ wchar_t szSubkey[MAX_PATH];
+
+ // If pszFileType starts with '.', try to read the default value of the
+ // HKCR\ key which contains the ProgID to which the file type
+ // is linked.
+ if (*pszFileType == L'.')
+ {
+ wchar_t szDefaultVal[260];
+ hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
+ sizeof(szDefaultVal));
+
+ // If the key exists and its default value is not empty, use the
+ // ProgID as the file type.
+ if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
+ {
+ pszFileType = szDefaultVal;
+ }
+ }
+
+ // Remove the HKCR\\shellex\DragDropHandlers\{} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
+ #ifdef CATCHCOPY_ROOT_MODE
+ L"%s\\shellex\\DragDropHandlers\\%s"
+ #else
+ L"Software\\Classes\\%s\\shellex\\DragDropHandlers\\%s"
+ #endif
+ , pszFileType, szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ hr = HRESULT_FROM_WIN32(RecursiveDeleteKey(
+ #ifdef CATCHCOPY_ROOT_MODE
+ HKEY_CLASSES_ROOT
+ #else
+ HKEY_CURRENT_USER
+ #endif
+ , szSubkey));
+ }
+
+ return hr;
+}
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Reg.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Reg.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Reg.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Reg.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,103 @@
+#ifndef _REG_H_
+#define _REG_H_
+#pragma once
+
+//#define CATCHCOPY_ROOT_MODE
+
+#include
+#include
+//
+// FUNCTION: RegisterInprocServer
+//
+// PURPOSE: Register the in-process component in the registry.
+//
+// PARAMETERS:
+// * pszModule - Path of the module that contains the component
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+// * pszThreadModel - Threading model
+//
+// NOTE: The function creates the HKCR\CLSID\{} key in the registry.
+//
+// HKCR
+// {
+// NoRemove CLSID
+// {
+// ForceRemove {} = s ''
+// {
+// InprocServer32 = s '%MODULE%'
+// {
+// val ThreadingModel = s ''
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid,
+ PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
+
+
+//
+// FUNCTION: UnregisterInprocServer
+//
+// PURPOSE: Unegister the in-process component in the registry.
+//
+// PARAMETERS:
+// * clsid - Class ID of the component
+//
+// NOTE: The function deletes the HKCR\CLSID\{} key in the registry.
+//
+HRESULT UnregisterInprocServer(const CLSID& clsid);
+
+
+//
+// FUNCTION: RegisterShellExtContextMenuHandler
+//
+// PURPOSE: Register the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+// * pszFriendlyName - Friendly name
+//
+// NOTE: The function creates the following key in the registry.
+//
+// HKCR
+// {
+// NoRemove
+// {
+// NoRemove shellex
+// {
+// NoRemove ContextMenuHandlers
+// {
+// {} = s ''
+// }
+// }
+// }
+// }
+//
+HRESULT RegisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
+
+
+//
+// FUNCTION: UnregisterShellExtContextMenuHandler
+//
+// PURPOSE: Unregister the context menu handler.
+//
+// PARAMETERS:
+// * pszFileType - The file type that the context menu handler is
+// associated with. For example, '*' means all file types; '.txt' means
+// all .txt files. The parameter must not be NULL.
+// * clsid - Class ID of the component
+//
+// NOTE: The function removes the {} key under
+// HKCR\\shellex\ContextMenuHandlers in the registry.
+//
+HRESULT UnregisterShellExtContextMenuHandler(
+ PCWSTR pszFileType, const CLSID& clsid);
+
+LONG RecursiveDeleteKey(HKEY hKeyParent, PCWSTR szKeyChild);
+#endif //_REG_H_
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/resource.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/resource.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/resource.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/resource.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by CatchCopy.rc
+//
+#define IDS_PROJNAME 100
+#define IDR_CATCHCOPY 101
+#define IDR_DDSHELLEXT 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 201
+#define _APS_NEXT_COMMAND_VALUE 32768
+#define _APS_NEXT_CONTROL_VALUE 201
+#define _APS_NEXT_SYMED_VALUE 103
+#endif
+#endif
diff -Nru ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Variable.h ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Variable.h
--- ultracopier-1.6.1.3/catchcopy-windows-explorer-plugin/Variable.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/catchcopy-windows-explorer-plugin/Variable.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,7 @@
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+/// \brief Un-comment this next line to put ultracopier in debug mode
+//#define CATCHCOPY_EXPLORER_PLUGIN_DEBUG
+
+#endif // VARIABLE_H
diff -Nru ultracopier-1.6.1.3/CompilerInfo.h ultracopier-2.2.4.4/CompilerInfo.h
--- ultracopier-1.6.1.3/CompilerInfo.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/CompilerInfo.h 2010-01-01 04:00:00.000000000 +0000
@@ -3,6 +3,8 @@
\author alpha_one_x86
\licence GPL3, see the file COPYING */
+#include
+
/// \def COMPILERINFO the string to identify the compiler
#if defined(Q_CC_GNU)
#define COMPILERINFO std::string("GCC ")+std::to_string(__GNUC__)+"."+std::to_string(__GNUC_MINOR__)+"."+std::to_string(__GNUC_PATCHLEVEL__)
diff -Nru ultracopier-1.6.1.3/CopyEngineManager.cpp ultracopier-2.2.4.4/CopyEngineManager.cpp
--- ultracopier-1.6.1.3/CopyEngineManager.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/CopyEngineManager.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -10,7 +10,7 @@
#include "cpp11addition.h"
#ifdef ULTRACOPIER_PLUGIN_ALL_IN_ONE_DIRECT
-#include "plugins/CopyEngine/Ultracopier/CopyEngineFactory.h"
+#include "plugins/CopyEngine/Ultracopier-Spec/CopyEngineFactory.h"
#endif
CopyEngineManager::CopyEngineManager(OptionDialog *optionDialog)
@@ -221,6 +221,7 @@
pluginList[index].intances.push_back(pluginList.at(index).factory->getInstance());
temp.engine=pluginList.at(index).intances.back();
temp.canDoOnlyCopy=pluginList.at(index).canDoOnlyCopy;
+ temp.havePause=pluginList.at(index).factory->havePause();
temp.type=pluginList.at(index).type;
temp.transferListOperation=pluginList.at(index).transferListOperation;
return temp;
@@ -262,10 +263,13 @@
temp.engine=NULL;
return temp;
}
- pluginList[index].intances.push_back(pluginList.at(index).factory->getInstance());
+ PluginInterface_CopyEngineFactory * factory=pluginList.at(index).factory;
+ PluginInterface_CopyEngine * newIntance=factory->getInstance();
+ pluginList[index].intances.push_back(newIntance);
temp.engine=pluginList.at(index).intances.back();
temp.canDoOnlyCopy=pluginList.at(index).canDoOnlyCopy;
temp.type=pluginList.at(index).type;
+ temp.havePause=factory->havePause();
temp.transferListOperation=pluginList.at(index).transferListOperation;
return temp;
}
diff -Nru ultracopier-1.6.1.3/CopyEngineManager.h ultracopier-2.2.4.4/CopyEngineManager.h
--- ultracopier-1.6.1.3/CopyEngineManager.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/CopyEngineManager.h 2010-01-01 04:00:00.000000000 +0000
@@ -34,6 +34,7 @@
{
PluginInterface_CopyEngine * engine; ///< The copy engine instance
bool canDoOnlyCopy; ///< true if can do only the copy (not move)
+ bool havePause;
Ultracopier::CopyType type; ///< Kind of copy what it can do
Ultracopier::TransferListOperation transferListOperation;
};
diff -Nru ultracopier-1.6.1.3/CopyListener.cpp ultracopier-2.2.4.4/CopyListener.cpp
--- ultracopier-1.6.1.3/CopyListener.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/CopyListener.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -16,6 +16,7 @@
CopyListener::CopyListener(OptionDialog *optionDialog)
{
+ nextOrderId=1;
stopIt=false;
this->optionDialog=optionDialog;
pluginLoader=new PluginLoaderCore(optionDialog);
diff -Nru ultracopier-1.6.1.3/Core.cpp ultracopier-2.2.4.4/Core.cpp
--- ultracopier-1.6.1.3/Core.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/Core.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -22,6 +22,9 @@
connect(ThemesManager::themesManager, &ThemesManager::theThemeNeedBeUnloaded, this, &Core::unloadInterface);
connect(ThemesManager::themesManager, &ThemesManager::theThemeIsReloaded, this, &Core::loadInterface, Qt::QueuedConnection);
connect(&forUpateInformation, &QTimer::timeout, this, &Core::periodicSynchronization);
+ #ifndef NOAUDIO
+ audio=nullptr;
+ #endif
}
Core::~Core()
@@ -35,6 +38,13 @@
delete copyList.at(index).engine;
index++;
}
+ #ifndef NOAUDIO
+ if(audio!=nullptr)
+ {
+ audio->stop();
+ delete audio;
+ }
+ #endif
}
void Core::newCopyWithoutDestination(const uint32_t &orderId,const std::vector &protocolsUsedForTheSources,const std::vector &sources)
@@ -355,6 +365,7 @@
newItem.action=Ultracopier::Idle;
newItem.lastProgression=0;//store the real byte transfered, used in time remaining calculation
newItem.isPaused=false;
+ newItem.havePause=returnInformations.havePause;
newItem.isRunning=false;
newItem.haveError=false;
newItem.lastConditionalSync.start();
@@ -461,7 +472,7 @@
{
case Ultracopier::RemainingTimeAlgo_Logarithmic:
if(copyInstance.remainingTimeLogarithmicValue.size()(timeUnit.first/timeUnit.second));
if(remainingTimeLogarithmicColumn.lastProgressionSpeed.size()>ULTRACOPIER_MAXVALUESPEEDSTORED)
- remainingTimeLogarithmicColumn.lastProgressionSpeed.pop_back();
+ remainingTimeLogarithmicColumn.lastProgressionSpeed.erase(remainingTimeLogarithmicColumn.lastProgressionSpeed.begin());
}
}
sub_index++;
@@ -536,6 +547,25 @@
copyList[index].orderId.clear();
resetSpeedDetected(index);
}
+ #ifndef NOAUDIO
+ if(action==Ultracopier::Idle)
+ if(stringtobool(OptionEngine::optionEngine->getOptionValue("Ultracopier","soundWhenFinish")))
+ {
+ const std::string newSoundFile=OptionEngine::optionEngine->getOptionValue("Ultracopier","soundFile");
+ if(newSoundFile!=soundFile)
+ {
+ if(audio!=nullptr)
+ delete audio;
+ audio=static_cast(FacilityEngine::facilityEngine.prepareOpusAudio(newSoundFile,buffer));
+ soundFile=newSoundFile;
+ }
+ if(audio!=nullptr)
+ {
+ buffer.seek(0);
+ audio->start(&buffer);
+ }
+ }
+ #endif
}
else
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"unable to locate the interface sender");
@@ -702,14 +732,17 @@
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"error at connect, the interface can not work correctly: "+std::to_string(index)+": "+std::to_string((uint64_t)sender())+" for pushGeneralProgression()");
if(!connect(currentCopyInstance.engine,&PluginInterface_CopyEngine::pushGeneralProgression, this,&Core::pushGeneralProgression, Qt::QueuedConnection))
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"error at connect, the interface can not work correctly: "+std::to_string(index)+": "+std::to_string((uint64_t)sender())+" for pushGeneralProgression() for this");
- if(!connect(currentCopyInstance.engine,&PluginInterface_CopyEngine::errorToRetry, currentCopyInstance.interface,&PluginInterface_Themes::errorToRetry, Qt::QueuedConnection))
+ if(!connect(currentCopyInstance.engine,&PluginInterface_CopyEngine::errorToRetry, currentCopyInstance.interface,&PluginInterface_Themes::errorToRetry, Qt::QueuedConnection))
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"error at connect, the interface can not work correctly: "+std::to_string(index)+": "+std::to_string((uint64_t)sender())+" for errorToRetry() for this");
+ if(!connect(currentCopyInstance.engine,&PluginInterface_CopyEngine::doneTime, currentCopyInstance.interface,&PluginInterface_Themes::doneTime,Qt::QueuedConnection))
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Critical,"error at connect, the engine can not work correctly: "+std::to_string(index)+": "+std::to_string((uint64_t)sender())+" for doneTime()");
currentCopyInstance.interface->setSupportSpeedLimitation(currentCopyInstance.engine->supportSpeedLimitation());
currentCopyInstance.interface->setCopyType(currentCopyInstance.type);
currentCopyInstance.interface->setTransferListOperation(currentCopyInstance.transferListOperation);
currentCopyInstance.interface->actionInProgess(currentCopyInstance.action);
currentCopyInstance.interface->isInPause(currentCopyInstance.isPaused);
+ currentCopyInstance.interface->havePause(currentCopyInstance.havePause);
if(currentCopyInstance.haveError)
currentCopyInstance.interface->errorDetected();
QWidget *tempWidget=currentCopyInstance.interface->getOptionsEngineWidget();
@@ -848,8 +881,12 @@
average_speed+=remainingTimeLogarithmicColumn.lastProgressionSpeed.at(temp_loop_index);
temp_loop_index++;
}
- average_speed/=remainingTimeLogarithmicColumn.lastProgressionSpeed.size();
- remainingTimeValue+=remainingSize/average_speed;
+ if(!remainingTimeLogarithmicColumn.lastProgressionSpeed.empty())
+ {
+ average_speed/=remainingTimeLogarithmicColumn.lastProgressionSpeed.size();
+ if(average_speed!=0)
+ remainingTimeValue+=remainingSize/average_speed;
+ }
}
//fallback
else
@@ -860,7 +897,10 @@
if(currentCopyInstance.totalProgression==0 || currentCopyInstance.currentProgression==0)
remainingTimeValue+=1;
else if((currentCopyInstance.totalProgression-currentCopyInstance.currentProgression)>1024)
- remainingTimeValue+=remainingSize/totAverageSpeed;
+ {
+ if(totAverageSpeed!=0)
+ remainingTimeValue+=remainingSize/totAverageSpeed;
+ }
}
else
remainingTimeValue+=1;
diff -Nru ultracopier-1.6.1.3/Core.h ultracopier-2.2.4.4/Core.h
--- ultracopier-1.6.1.3/Core.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/Core.h 2010-01-01 04:00:00.000000000 +0000
@@ -14,6 +14,10 @@
#include
#include
#include
+#ifndef NOAUDIO
+#include
+#include
+#endif
#include "Environment.h"
#include "StructEnumDefinition.h"
@@ -64,6 +68,7 @@
std::string collisionAction;
std::string errorAction;
bool isPaused;
+ bool havePause;
bool isRunning;
Ultracopier::CopyType type;
Ultracopier::TransferListOperation transferListOperation;
@@ -129,6 +134,12 @@
LogThread log;///< To save the log like mkpath, rmpath, error, copy, ...
uint64_t realByteTransfered;
+ #ifndef NOAUDIO
+ QBuffer buffer;
+ QAudioOutput *audio;
+ std::string soundFile;
+ #endif
+
static uint8_t fileCatNumber(uint64_t size);
signals:
void copyFinished(const uint32_t & orderId,bool withError) const;
diff -Nru ultracopier-1.6.1.3/cpp11addition.cpp ultracopier-2.2.4.4/cpp11addition.cpp
--- ultracopier-1.6.1.3/cpp11addition.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/cpp11addition.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -214,7 +214,7 @@
std::string binarytoHexa(const void * const data, const uint32_t &size, bool *ok)
{
- return binarytoHexa(reinterpret_cast(data),size,ok);
+ return binarytoHexa(reinterpret_cast(data),size,ok);
}
std::string binarytoHexa(const char * const data, const uint32_t &size, bool *ok)
@@ -476,6 +476,69 @@
return tempFile;
}
+std::wstring FSabsoluteFilePath(const std::wstring &string)
+{
+ std::wstring newstring=string;
+ #ifdef _WIN32
+ stringreplaceAll(newstring,L"\\",L"/");
+ #endif
+ stringreplaceAll(newstring,L"//",L"/");
+ std::vector parts=stringsplit(newstring,'/');
+
+ #ifndef _WIN32
+ unsigned int index=1;
+ #else
+ unsigned int index=2;
+ #endif
+ while(index0 && (index>1 || !parts.at(index-1).empty()))
+ #else
+ if(index>1)
+ #endif
+ {
+ parts.erase(parts.begin()+index-1);
+ index--;
+ }
+ }
+ else
+ index++;
+ }
+
+ #ifndef _WIN32
+ if(parts.empty() || (parts.size()==1 && parts.at(0).empty()))
+ return L"/";
+ #endif
+
+ std::wstring newString;
+ std::vector copy=parts;
+ unsigned int count=0;
+ while(!copy.empty())
+ {
+ if(count>0)
+ newString+=L'/';
+ newString+=copy.front();
+ copy.erase(copy.begin());
+ ++count;
+ }
+
+ return newString;
+}
+
+std::wstring FSabsolutePath(const std::wstring &string)
+{
+ const std::wstring &tempFile=FSabsoluteFilePath(string);
+ const std::size_t &found=tempFile.find_last_of(L"/\\");
+ if(found!=std::wstring::npos)
+ return tempFile.substr(0,found)+L'/';
+ else
+ return tempFile;
+}
+
uint64_t msFrom1970()
{
return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count();
@@ -501,16 +564,22 @@
std::vector returnedVar;
size_t start_pos = 0;
size_t firstChar = 0;
- while((start_pos = string.find(',', start_pos)) != std::string::npos) {
- if(start_pos==0 || string.at(start_pos-1)!=',')
+ do
+ {
+ size_t s=start_pos = string.find(',', start_pos);
+ if(s == std::string::npos)
+ start_pos=string.size();
+ if(start_pos>=string.size() || string.at(start_pos+1)!=',')
{
- std::string tempString=string.substr(firstChar,start_pos-1);
+ std::string tempString=string.substr(firstChar,start_pos-firstChar);
stringreplaceAll(tempString,",,",",");
returnedVar.push_back(tempString);
start_pos++;
firstChar=start_pos;
}
- }
+ else
+ start_pos+=2;
+ } while(firstChar= ending.length()) {
+ return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
+ } else {
+ return false;
+ }
+}
+
+bool stringEndsWith(std::wstring const &fullString, char const &ending)
+{
+ if (fullString.length()>0) {
+ return fullString[fullString.size()-1]==ending;
+ } else {
+ return false;
+ }
+}
+
+bool stringStartWith(std::wstring const &fullString, std::wstring const &starting)
+{
+ if (fullString.length() >= starting.length()) {
+ return (fullString.substr(0,starting.length())==starting);
+ } else {
+ return false;
+ }
+}
+
+bool stringStartWith(std::wstring const &fullString, char const &starting)
+{
+ if (fullString.length()>0) {
+ return fullString[0]==starting;
+ } else {
+ return false;
+ }
+}
+
+std::vector stringsplit(const std::wstring &s, wchar_t delim)
+{
+ std::vector elems;
+
+ std::wstring::size_type i = 0;
+ std::wstring::size_type j = s.find(delim);
+
+ if(j == std::wstring::npos)
+ {
+ if(!s.empty())
+ elems.push_back(s);
+ return elems;
+ }
+ else
+ {
+ while (j != std::wstring::npos) {
+ elems.push_back(s.substr(i, j-i));
+ i = ++j;
+ j = s.find(delim, j);
+
+ if (j == std::wstring::npos)
+ elems.push_back(s.substr(i, s.length()));
+ }
+ return elems;
+ }
+}
diff -Nru ultracopier-1.6.1.3/cpp11addition.h ultracopier-2.2.4.4/cpp11addition.h
--- ultracopier-1.6.1.3/cpp11addition.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/cpp11addition.h 2010-01-01 04:00:00.000000000 +0000
@@ -39,6 +39,14 @@
std::string stringimplode(const std::queue& elems, char delim);
std::string stringimplode(const std::vector& elems, const std::string &delim);
+bool stringreplaceOne(std::wstring& str, const std::wstring& from, const std::wstring& to);
+uint8_t stringreplaceAll(std::wstring& str, const std::wstring& from, const std::wstring& to);
+bool stringEndsWith(std::wstring const &fullString, std::wstring const &ending);
+bool stringEndsWith(std::wstring const &fullString, char const &ending);
+bool stringStartWith(std::wstring const &fullString, std::wstring const &starting);
+bool stringStartWith(std::wstring const &fullString, char const &starting);
+std::vector stringsplit(const std::wstring &s, wchar_t delim);
+
uint8_t stringtouint8(const std::string &string,bool *ok=NULL);
uint16_t stringtouint16(const std::string &string,bool *ok=NULL);
uint32_t stringtouint32(const std::string &string,bool *ok=NULL);
@@ -65,6 +73,8 @@
std::vector base64toBinary(const std::string &string);
std::string FSabsoluteFilePath(const std::string &string);
std::string FSabsolutePath(const std::string &string);
+std::wstring FSabsoluteFilePath(const std::wstring &string);
+std::wstring FSabsolutePath(const std::wstring &string);
uint64_t msFrom1970();
uint64_t sFrom1970();
diff -Nru ultracopier-1.6.1.3/debian/changelog ultracopier-2.2.4.4/debian/changelog
--- ultracopier-1.6.1.3/debian/changelog 2020-03-23 06:28:08.000000000 +0000
+++ ultracopier-2.2.4.4/debian/changelog 2020-08-13 20:26:39.000000000 +0000
@@ -1,8 +1,25 @@
-ultracopier (1.6.1.3-1build1) focal; urgency=medium
+ultracopier (2.2.4.4-1) unstable; urgency=medium
- * No-change rebuild for libgcc-s1 package name change.
+ * New upstream release.
+ * debian/copyright:
+ + Update copyright info to reflect new release.
+ * debian/rules:
+ + Fix path to CopyEngine.pro.
+ + Make use of execute_after and execute_before targets.
+ + Remove stale line about detect_arch.
+ + Export qmake cross wrapper in QMAKE to fix cross builds (Closes:
+ #968214).
+ * debian/control:
+ + Add missing qtmultimedia5-dev and libopus-dev build-dependencies.
+ + Build-depend on debhelper-compat 13.
+ + Bump Standard-Version to 4.5.0 (no changes needed).
+ + Set Rules-Requires-Root to no.
+ * debian/compat:
+ + Remove.
+ * debian/upstream/metadata:
+ + Document upstream information.
- -- Matthias Klose Mon, 23 Mar 2020 07:28:08 +0100
+ -- Thomas Preud'homme Thu, 13 Aug 2020 21:26:39 +0100
ultracopier (1.6.1.3-1) unstable; urgency=medium
diff -Nru ultracopier-1.6.1.3/debian/compat ultracopier-2.2.4.4/debian/compat
--- ultracopier-1.6.1.3/debian/compat 2019-02-03 21:37:22.000000000 +0000
+++ ultracopier-2.2.4.4/debian/compat 1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-11
diff -Nru ultracopier-1.6.1.3/debian/control ultracopier-2.2.4.4/debian/control
--- ultracopier-1.6.1.3/debian/control 2019-02-03 21:37:22.000000000 +0000
+++ ultracopier-2.2.4.4/debian/control 2020-08-13 20:26:39.000000000 +0000
@@ -2,9 +2,10 @@
Section: utils
Priority: optional
Maintainer: Thomas Preud'homme
-Build-Depends: debhelper (>= 11), qtbase5-dev, qt5-qmake,
- qttools5-dev-tools
-Standards-Version: 4.3.0
+Build-Depends: debhelper-compat (= 13), qtbase5-dev, qt5-qmake,
+ qttools5-dev-tools, qtmultimedia5-dev, libopus-dev
+Standards-Version: 4.5.0
+Rules-Requires-Root: no
Homepage: http://ultracopier.first-world.info/
Vcs-Git: https://salsa.debian.org/debian/ultracopier.git
Vcs-Browser: https://salsa.debian.org/debian/ultracopier
diff -Nru ultracopier-1.6.1.3/debian/copyright ultracopier-2.2.4.4/debian/copyright
--- ultracopier-1.6.1.3/debian/copyright 2019-02-03 21:37:22.000000000 +0000
+++ ultracopier-2.2.4.4/debian/copyright 2020-08-13 20:26:39.000000000 +0000
@@ -1,15 +1,16 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Ultracopier
Upstream-Contact: Herman Brule
-Source: http://files.first-world.info/ultracopier/
+Source: https://ultracopier.first-world.info/download-all.html
License: GPL-3
Files: *
-Copyright: 2010-2017 Herman Brule
+Copyright: 2010-2019 Herman Brule
+ lculator zaloom
License: GPL-3
Files: debian/*
-Copyright: 2010-2018 Thomas Preud'homme
+Copyright: 2010-2020 Thomas Preud'homme
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +39,7 @@
2007 Riccardo Iaconelli
License: LGPL-3+
-Files: plugins/Languages/*.png ./resources/Languages/*.png
+Files: plugins/Languages/*.png resources/Languages/*.png
Copyright: 2012 Matthieu Aubry
License: GPL-3+
@@ -50,6 +51,65 @@
want with it. All the files in XZ Embedded have been written by Lasse Collin,
but some files are heavily based on public domain code written by Igor Pavlov.
+Files: test/radialmap/*
+ plugins/Themes/Oxygen2/radialMap/*
+ plugins/Themes/Oxygen2/fileTree.*
+Copyright: 2003-2004 Max Howell
+ 2008-2009 Martin Sandsmark
+License: GPL-2 or GPL-3+
+
+Files: libogg/*
+Copyright: 2002 Xiph.org Foundation
+License: BSD-3-clause
+
+Files: opusfile/*
+Copyright: 1994-2002 Xiph.org Foundation
+License: BSD-3-clause
+
+License: BSD-3-clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ .
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ .
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ .
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+License: GPL-2
+ 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, version 2 of the License.
+ .
+ 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 this program. If not, see .
+ .
+ On Debian systems, the full text of the GNU General Public License version 2
+ can be found in the file `/usr/share/common-licenses/GPL-2'.
+
License: GPL-3
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
diff -Nru ultracopier-1.6.1.3/debian/.git-dpm ultracopier-2.2.4.4/debian/.git-dpm
--- ultracopier-1.6.1.3/debian/.git-dpm 2019-02-03 21:37:22.000000000 +0000
+++ ultracopier-2.2.4.4/debian/.git-dpm 2020-08-13 20:26:39.000000000 +0000
@@ -1,8 +1,8 @@
# see git-dpm(1) from git-dpm package
-9b10c21f5cad0e2ec27d23c59e65af7141a226f3
-9b10c21f5cad0e2ec27d23c59e65af7141a226f3
-9b10c21f5cad0e2ec27d23c59e65af7141a226f3
-9b10c21f5cad0e2ec27d23c59e65af7141a226f3
-ultracopier_1.6.1.3.orig.tar.xz
-12b2e37792174602fe97b4a0f1ee82d472a7d5fc
-650008
+3ac113857071fc1f225b2e1b42547269e568c6b7
+3ac113857071fc1f225b2e1b42547269e568c6b7
+3ac113857071fc1f225b2e1b42547269e568c6b7
+3ac113857071fc1f225b2e1b42547269e568c6b7
+ultracopier_2.2.4.4.orig.tar.xz
+9c95f787c443c25ec28e7da08ac304af03041c1a
+1484020
diff -Nru ultracopier-1.6.1.3/debian/rules ultracopier-2.2.4.4/debian/rules
--- ultracopier-1.6.1.3/debian/rules 2019-02-03 21:37:22.000000000 +0000
+++ ultracopier-2.2.4.4/debian/rules 2020-08-13 20:26:39.000000000 +0000
@@ -6,9 +6,14 @@
export QT_SELECT:=qt5
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+# Export qmake cross wrapper in QMAKE to allow lrelease to work in case of
+# cross-build.
+include /usr/share/dpkg/buildtools.mk
+export QMAKE
+
override_dh_auto_configure:
lrelease ultracopier.pro
- lrelease plugins/CopyEngine/Ultracopier/CopyEngine.pro
+ lrelease plugins/CopyEngine/Ultracopier-Spec/CopyEngine.pro
lrelease plugins/Themes/Oxygen/interface.pro
# Ensure QM file timestamps are stable over time because they get
# picked up by rcc in files generated from QRC resource file when they
@@ -22,14 +27,13 @@
target.path=/usr/bin "INSTALLS+=target" \
ultracopier.pro
-clean:
+execute_before_clean:
rm -f build
- dh clean --buildsystem=qmake
+
+execute_after_clean:
find -name \*.qm -delete
- rm -f debian/detect_arch
-build:
- dh build --buildsystem=qmake
+execute_after_build:
touch build
%:
diff -Nru ultracopier-1.6.1.3/debian/upstream/metadata ultracopier-2.2.4.4/debian/upstream/metadata
--- ultracopier-1.6.1.3/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/debian/upstream/metadata 2020-08-13 20:26:39.000000000 +0000
@@ -0,0 +1,7 @@
+---
+Documentation: http://ultracopier-wiki.first-world.info/wiki/Ultracopier_wiki
+Donation: http://ultracopier-wiki.first-world.info/wiki/Ultracopier_wiki
+FAQ: http://ultracopier.first-world.info/faq.html
+Repository: https://github.com/alphaonex86/Ultracopier.git
+Repository-Browse: https://github.com/alphaonex86/Ultracopier
+Screenshots: http://ultracopier.first-world.info/screenshots.html
diff -Nru ultracopier-1.6.1.3/DebugEngine.cpp ultracopier-2.2.4.4/DebugEngine.cpp
--- ultracopier-1.6.1.3/DebugEngine.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/DebugEngine.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -14,11 +14,15 @@
#include "DebugEngine.h"
#include "ExtraSocket.h"
#include "cpp11addition.h"
+#include "FacilityEngine.h"
#ifdef WIN32
# define __func__ __FUNCTION__
#endif
+#ifdef ULTRACOPIER_DEBUGCONSOLE
+#undef ULTRACOPIER_DEBUGCONSOLE
+#endif
/// \brief The local macro: ULTRACOPIER_DEBUGCONSOLE
#if defined (__FILE__) && defined (__LINE__)
# define ULTRACOPIER_DEBUGCONSOLE(a,b) addDebugInformation(a,__func__,b,__FILE__,__LINE__)
@@ -59,7 +63,7 @@
debugHtmlContent+="";
debugHtmlContent+="";
debugHtmlContent+="Ultracopier";
- debugHtmlContent+=" "+std::string(ULTRACOPIER_VERSION)+" "+ULTRACOPIER_PLATFORM_NAME.toStdString()+", debug report";
+ debugHtmlContent+=" "+FacilityEngine::version()+" "+ULTRACOPIER_PLATFORM_NAME.toStdString()+", debug report";
debugHtmlContent+="";
debugHtmlContent+="";
debugHtmlContent+="";
@@ -335,7 +339,7 @@
if(addDebugInformationCallNumberaddDebugInformation(startTime.elapsed(),level,function,text,file,static_cast(ligne),location);
+ DebugModel::debugModel->addDebugInformation(startTime.elapsed(),level,function,text,file,static_cast(ligne),location);
}
}
}
diff -Nru ultracopier-1.6.1.3/DebugEngineMacro.h ultracopier-2.2.4.4/DebugEngineMacro.h
--- ultracopier-1.6.1.3/DebugEngineMacro.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/DebugEngineMacro.h 2010-01-01 04:00:00.000000000 +0000
@@ -12,6 +12,9 @@
#include "Variable.h"
+#ifdef ULTRACOPIER_DEBUGCONSOLE
+#undef ULTRACOPIER_DEBUGCONSOLE
+#endif
/// \brief Macro for the debug log
#ifdef ULTRACOPIER_DEBUG
# include "DebugEngine.h"
diff -Nru ultracopier-1.6.1.3/EventDispatcher.cpp ultracopier-2.2.4.4/EventDispatcher.cpp
--- ultracopier-1.6.1.3/EventDispatcher.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/EventDispatcher.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -28,8 +28,6 @@
#include
#include
#include
- typedef void (WINAPI *PGNSI) (LPSYSTEM_INFO);
- typedef BOOL (WINAPI *PGPI) (DWORD, DWORD, DWORD, DWORD, PDWORD);
#endif
#ifdef Q_OS_MAC
#include
@@ -51,6 +49,7 @@
qRegisterMetaType >("std::vector");
qRegisterMetaType >("std::vector");
qRegisterMetaType >("std::vector");
+ qRegisterMetaType("QLocalSocket::LocalSocketError");
copyServer=new CopyListener(&optionDialog);
if(!connect(&localListener, &LocalListener::cli, &cliParser, &CliParser::cli,Qt::QueuedConnection))
@@ -113,7 +112,7 @@
#ifdef __STDC_VERSION__
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,"__STDC_VERSION__: "+std::to_string(__STDC_VERSION__));
#endif
- ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,std::string("ULTRACOPIER_VERSION: ")+ULTRACOPIER_VERSION);
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,std::string("ULTRACOPIER_VERSION: ")+FacilityEngine::version());
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,std::string("Qt version: ")+qVersion()+" "+std::to_string(QT_VERSION));
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,std::string("ULTRACOPIER_PLATFORM_NAME: ")+ULTRACOPIER_PLATFORM_NAME.toStdString());
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,"Application path: "+QCoreApplication::applicationFilePath().toStdString()+" "+std::to_string(QCoreApplication::applicationPid()));
@@ -139,7 +138,24 @@
int index=0;
while(indexgetOptionValue("Ultracopier","Last_version_used")!="na" && OptionEngine::optionEngine->getOptionValue("Ultracopier","Last_version_used")!=ULTRACOPIER_VERSION)
+ if(OptionEngine::optionEngine->getOptionValue("Ultracopier","Last_version_used")!="na" && OptionEngine::optionEngine->getOptionValue("Ultracopier","Last_version_used")!=FacilityEngine::version())
{
//then ultracopier have been updated
}
- OptionEngine::optionEngine->setOptionValue("Ultracopier","Last_version_used",ULTRACOPIER_VERSION);
+ OptionEngine::optionEngine->setOptionValue("Ultracopier","Last_version_used",FacilityEngine::version());
unsigned int a=stringtouint32(OptionEngine::optionEngine->getOptionValue("Ultracopier","ActionOnManualOpen"));
if(a>2)
OptionEngine::optionEngine->setOptionValue("Ultracopier","ActionOnManualOpen","1");
@@ -393,10 +409,7 @@
QString Os;
OSVERSIONINFOEX osvi;
SYSTEM_INFO si;
- PGNSI pGNSI;
- PGPI pGPI;
BOOL bOsVersionInfoEx;
- DWORD dwType;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
@@ -406,15 +419,7 @@
if(bOsVersionInfoEx == 0)
return "Os detection blocked";
-
- // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
-
- pGNSI = (PGNSI) GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")),
- "GetNativeSystemInfo");
- if(NULL != pGNSI)
- pGNSI(&si);
- else GetSystemInfo(&si);
+ GetNativeSystemInfo(&si);
if(VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion>4)
{
@@ -443,70 +448,6 @@
else Os+=QStringLiteral("Windows Server (dwMajorVersion: %1, dwMinorVersion: %2)").arg(osvi.dwMinorVersion).arg(osvi.dwMinorVersion);
break;
}
-
- pGPI = (PGPI) GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")),
- "GetProductInfo");
-
- pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
-
- switch(dwType)
- {
- case PRODUCT_ULTIMATE:
- Os+=QStringLiteral("Ultimate Edition");
- break;
- case PRODUCT_PROFESSIONAL:
- Os+=QStringLiteral("Professional");
- break;
- case PRODUCT_HOME_PREMIUM:
- Os+=QStringLiteral("Home Premium Edition");
- break;
- case PRODUCT_HOME_BASIC:
- Os+=QStringLiteral("Home Basic Edition");
- break;
- case PRODUCT_ENTERPRISE:
- Os+=QStringLiteral("Enterprise Edition");
- break;
- case PRODUCT_BUSINESS:
- Os+=QStringLiteral("Business Edition");
- break;
- case PRODUCT_STARTER:
- Os+=QStringLiteral("Starter Edition");
- break;
- case PRODUCT_CLUSTER_SERVER:
- Os+=QStringLiteral("Cluster Server Edition");
- break;
- case PRODUCT_DATACENTER_SERVER:
- Os+=QStringLiteral("Datacenter Edition");
- break;
- case PRODUCT_DATACENTER_SERVER_CORE:
- Os+=QStringLiteral("Datacenter Edition (core installation)");
- break;
- case PRODUCT_ENTERPRISE_SERVER:
- Os+=QStringLiteral("Enterprise Edition");
- break;
- case PRODUCT_ENTERPRISE_SERVER_CORE:
- Os+=QStringLiteral("Enterprise Edition (core installation)");
- break;
- case PRODUCT_ENTERPRISE_SERVER_IA64:
- Os+=QStringLiteral("Enterprise Edition for Itanium-based Systems");
- break;
- case PRODUCT_SMALLBUSINESS_SERVER:
- Os+=QStringLiteral("Small Business Server");
- break;
- case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
- Os+=QStringLiteral("Small Business Server Premium Edition");
- break;
- case PRODUCT_STANDARD_SERVER:
- Os+=QStringLiteral("Standard Edition");
- break;
- case PRODUCT_STANDARD_SERVER_CORE:
- Os+=QStringLiteral("Standard Edition (core installation)");
- break;
- case PRODUCT_WEB_SERVER:
- Os+=QStringLiteral("Web Server Edition");
- break;
- }
}
else if(osvi.dwMajorVersion==5)
{
diff -Nru ultracopier-1.6.1.3/FacilityEngine.cpp ultracopier-2.2.4.4/FacilityEngine.cpp
--- ultracopier-1.6.1.3/FacilityEngine.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/FacilityEngine.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -13,6 +13,11 @@
#endif
#include
#endif
+#ifndef NOAUDIO
+#include "opusfile/opusfile.h"
+#include
+#include
+#endif
FacilityEngine FacilityEngine::facilityEngine;
@@ -73,6 +78,7 @@
translations["Copying"]=tr("Copying").toStdString();
translations["Listing and copying"]=tr("Listing and copying").toStdString();
translations["Time remaining:"]=tr("Time remaining:").toStdString();
+ translations["Remaining:"]=tr("Remaining:").toStdString();
//for copy engine
translations["Ask"]=tr("Ask").toStdString();
translations["Skip"]=tr("Skip").toStdString();
@@ -230,21 +236,29 @@
/// \brief Return ultimate url, empty is not found or already ultimate
std::string FacilityEngine::ultimateUrl() const
{
+ #ifndef ULTRACOPIER_LITTLE
if(ProductKey::productKey->isUltimate())
return std::string();
else
{
- #if defined(Q_OS_WIN32) || defined(Q_OS_MAC)
+ #if ! defined(Q_OS_LINUX)
return "https://shop.first-world.info/";
#else
return std::string();
#endif
}
+ #else
+ return std::string();
+ #endif
}
bool FacilityEngine::isUltimate() const
{
+ #ifndef ULTRACOPIER_LITTLE
return ProductKey::productKey->isUltimate();
+ #else
+ return true;
+ #endif
}
/// \brief Return the software name
@@ -256,3 +270,90 @@
return "Ultracopier";
#endif
}
+
+/// \brief return audio if created from opus file, nullptr if failed
+void *FacilityEngine::prepareOpusAudio(const std::string &file,QBuffer &buffer) const
+{
+ #ifndef NOAUDIO
+ if(file.empty())
+ return nullptr;
+
+ QAudioOutput* audio;
+ QAudioFormat format;
+ format.setSampleRate(48000);
+ format.setChannelCount(2);
+ format.setSampleSize(16);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::SignedInt);
+
+ QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
+ if (!info.isFormatSupported(format)) {
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"raw audio format not supported by backend, cannot play audio.");
+ return nullptr;
+ }
+ audio = new QAudioOutput(format);
+ buffer.open(QBuffer::ReadWrite);
+
+ int ret;
+ std::string path=file;
+ if(path.find("/") == std::string::npos && path.find("\\") == std::string::npos)
+ {
+ QString appPath=QCoreApplication::applicationDirPath();
+ if(appPath.endsWith("/") || appPath.endsWith("\\"))
+ path=appPath.toStdString()+path;
+ else
+ path=appPath.toStdString()+"/"+path;
+ }
+ OggOpusFile *of=op_open_file(file.c_str(),&ret);
+ if(of==NULL) {
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"Failed to open file"+file+", "+std::to_string(ret));
+ return nullptr;
+ }
+ ogg_int64_t pcm_offset;
+ ogg_int64_t nsamples;
+ nsamples=0;
+ pcm_offset=op_pcm_tell(of);
+ if(pcm_offset!=0)
+ fprintf(stderr,"Non-zero starting PCM offset: %li\n",(long)pcm_offset);
+ for(;;) {
+ ogg_int64_t next_pcm_offset;
+ opus_int16 pcm[120*48*2];
+ unsigned char out[120*48*2*2];
+ int si;
+ ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm));
+ if(ret==OP_HOLE) {
+ fprintf(stderr,"\nHole detected! Corrupt file segment?\n");
+ continue;
+ }
+ else if(ret<0) {
+ fprintf(stderr,"\nError decoding '%s': %i\n","file.opus",ret);
+ ret=EXIT_FAILURE;
+ break;
+ }
+ next_pcm_offset=op_pcm_tell(of);
+ pcm_offset=next_pcm_offset;
+ if(ret<=0) {
+ ret=EXIT_SUCCESS;
+ break;
+ }
+ for(si=0;si<2*ret;si++) { /// Ensure the data is little-endian before writing it out.
+ out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
+ out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
+ }
+ buffer.write(reinterpret_cast(out),sizeof(*out)*4*ret);
+ nsamples+=ret;
+ }
+ if(ret==EXIT_SUCCESS)
+ fprintf(stderr,"\nDone: played ");
+ op_free(of);
+
+ buffer.seek(0);
+ return audio;
+ // audio->start(&buffer); -> do out of this function
+ #else
+ (void)file;
+ (void)buffer;
+ return nullptr;
+ #endif
+}
diff -Nru ultracopier-1.6.1.3/FacilityEngine.h ultracopier-2.2.4.4/FacilityEngine.h
--- ultracopier-1.6.1.3/FacilityEngine.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/FacilityEngine.h 2010-01-01 04:00:00.000000000 +0000
@@ -47,7 +47,10 @@
static std::string separator();
/// \brief return if is ultimate
bool isUltimate() const;
+ /// \brief return audio if created from opus file, nullptr if failed
+ void/*casted to #ifndef QAudioOutput*/* prepareOpusAudio(const std::string &file,QBuffer &buffer) const;
+ static std::string version();
static FacilityEngine facilityEngine;
private:
//undirect translated string
diff -Nru ultracopier-1.6.1.3/FacilityEngineVersion.cpp ultracopier-2.2.4.4/FacilityEngineVersion.cpp
--- ultracopier-1.6.1.3/FacilityEngineVersion.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/FacilityEngineVersion.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,7 @@
+#include "FacilityEngine.h"
+#include "Version.h"
+
+std::string FacilityEngine::version()
+{
+ return ULTRACOPIER_VERSION;
+}
diff -Nru ultracopier-1.6.1.3/file-manager/libfm-qt-uc.patch ultracopier-2.2.4.4/file-manager/libfm-qt-uc.patch
--- ultracopier-1.6.1.3/file-manager/libfm-qt-uc.patch 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/file-manager/libfm-qt-uc.patch 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,94 @@
+diff -ur libfm-qt-0.14.1/CMakeLists.txt libfm-qt-0.14.1-patched/CMakeLists.txt
+--- libfm-qt-0.14.1/CMakeLists.txt 2019-02-24 10:56:00.000000000 -0400
++++ libfm-qt-0.14.1-patched/CMakeLists.txt 2019-12-19 13:58:02.031193213 -0400
+@@ -34,6 +34,7 @@
+ find_package(Qt5Widgets "${QT_MINIMUM_VERSION}" REQUIRED)
+ find_package(Qt5LinguistTools "${QT_MINIMUM_VERSION}" REQUIRED)
+ find_package(Qt5X11Extras "${QT_MINIMUM_VERSION}" REQUIRED)
++find_package(Qt5Network "${QT_MINIMUM_VERSION}" REQUIRED)
+
+ find_package(lxqt-build-tools "${LXQTBT_MINIMUM_VERSION}" REQUIRED)
+ find_package(GLIB "${GLIB_MINIMUM_VERSION}" REQUIRED COMPONENTS gio gio-unix gobject gthread)
+diff -ur libfm-qt-0.14.1/src/utilities.cpp libfm-qt-0.14.1-patched/src/utilities.cpp
+--- libfm-qt-0.14.1/src/utilities.cpp 2019-02-24 10:56:00.000000000 -0400
++++ libfm-qt-0.14.1-patched/src/utilities.cpp 2019-12-19 16:25:07.811840646 -0400
+@@ -28,6 +28,7 @@
+ #include
+ #include "fileoperation.h"
+ #include
++#include
+
+ #include
+ #include
+@@ -95,6 +96,27 @@
+ return std::make_pair(paths, isCut);
+ }
+
++void sendRawOrderList(const QStringList & order, QLocalSocket &socket, int idNextOrder)
++{
++ QByteArray block;
++ QDataStream out(&block, QIODevice::WriteOnly);
++ out.setVersion(QDataStream::Qt_4_4);
++ out << int(0);
++ out << idNextOrder;
++ out << order;
++ out.device()->seek(0);
++ out << block.size();
++ do //cut string list and send it as block of 32KB
++ {
++ QByteArray blockToSend;
++ int byteWriten;
++ blockToSend=block.left(32*1024);//32KB
++ block.remove(0,blockToSend.size());
++ byteWriten = socket.write(blockToSend);
++ }
++ while(block.size());
++}
++
+ void pasteFilesFromClipboard(const Fm::FilePath& destPath, QWidget* parent) {
+ QClipboard* clipboard = QApplication::clipboard();
+ const QMimeData* data = clipboard->mimeData();
+@@ -104,12 +126,38 @@
+ std::tie(paths, isCut) = parseClipboardData(*data);
+
+ if(!paths.empty()) {
+- if(isCut) {
+- FileOperation::moveFiles(paths, destPath, parent);
+- clipboard->clear(QClipboard::Clipboard);
++ QLocalSocket socket;
++ socket.connectToServer(QString::fromStdString("advanced-copier-"+std::to_string(getuid())));
++ socket.waitForConnected();
++ if(socket.state()==QLocalSocket::ConnectedState)
++ {
++ sendRawOrderList(QStringList() << "protocol" << "0002", socket, 1);
++ socket.waitForReadyRead();
++ socket.readAll();
++ QStringList l;
++ if(isCut) {
++ l << "mv";
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ l << "cp";
++ }
++ for(const FilePath &n : paths)
++ l << n.toString().get();
++ l << destPath.toString().get();
++ sendRawOrderList(l, socket, 2);
++ socket.waitForBytesWritten();
++ socket.close();
+ }
+- else {
+- FileOperation::copyFiles(paths, destPath, parent);
++ else
++ {
++ if(isCut) {
++ FileOperation::moveFiles(paths, destPath, parent);
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ FileOperation::copyFiles(paths, destPath, parent);
++ }
+ }
+ }
+ }
diff -Nru ultracopier-1.6.1.3/file-manager/pcmanfm-qt.txt ultracopier-2.2.4.4/file-manager/pcmanfm-qt.txt
--- ultracopier-1.6.1.3/file-manager/pcmanfm-qt.txt 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/file-manager/pcmanfm-qt.txt 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,3 @@
+mkdir -v build;cd build;cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$LXQT_PREFIX -DPULL_TRANSLATIONS=no ..
+
+make
diff -Nru ultracopier-1.6.1.3/file-manager/pcmanfm-qt-uc.patch ultracopier-2.2.4.4/file-manager/pcmanfm-qt-uc.patch
--- ultracopier-1.6.1.3/file-manager/pcmanfm-qt-uc.patch 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/file-manager/pcmanfm-qt-uc.patch 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,191 @@
+diff -ur pcmanfm-qt-0.14.1/CMakeLists.txt pcmanfm-qt-patched/CMakeLists.txt
+--- pcmanfm-qt-0.14.1/CMakeLists.txt 2019-02-23 20:16:13.000000000 -0400
++++ pcmanfm-qt-patched/CMakeLists.txt 2019-12-19 17:16:14.796019382 -0400
+@@ -24,6 +24,7 @@
+ find_package(Qt5LinguistTools ${QT_MINIMUM_VERSION} REQUIRED)
+ find_package(Qt5Widgets ${QT_MINIMUM_VERSION} REQUIRED)
+ find_package(Qt5X11Extras ${QT_MINIMUM_VERSION} REQUIRED)
++find_package(Qt5Network "${QT_MINIMUM_VERSION}" REQUIRED)
+ find_package(fm-qt ${LIBFMQT_MINIMUM_VERSION} REQUIRED)
+ find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED)
+
+diff -ur pcmanfm-qt-0.14.1/pcmanfm/CMakeLists.txt pcmanfm-qt-patched/pcmanfm/CMakeLists.txt
+--- pcmanfm-qt-0.14.1/pcmanfm/CMakeLists.txt 2019-02-23 20:16:13.000000000 -0400
++++ pcmanfm-qt-patched/pcmanfm/CMakeLists.txt 2019-12-19 17:16:55.556039000 -0400
+@@ -79,6 +79,7 @@
+ Qt5::X11Extras
+ Qt5::Widgets
+ Qt5::DBus
++ Qt5::Network
+ fm-qt
+ )
+
+diff -ur pcmanfm-qt-0.14.1/pcmanfm/desktopwindow.cpp pcmanfm-qt-patched/pcmanfm/desktopwindow.cpp
+--- pcmanfm-qt-0.14.1/pcmanfm/desktopwindow.cpp 2019-02-23 20:16:13.000000000 -0400
++++ pcmanfm-qt-patched/pcmanfm/desktopwindow.cpp 2019-12-19 16:52:39.985314000 -0400
+@@ -40,6 +40,7 @@
+ #include
+ #include
+ #include
++#include
+
+ #include "./application.h"
+ #include "mainwindow.h"
+@@ -1324,11 +1325,73 @@
+ }
+ }
+
++void sendRawOrderList(const QStringList & order, QLocalSocket &socket, int idNextOrder)
++{
++ QByteArray block;
++ QDataStream out(&block, QIODevice::WriteOnly);
++ out.setVersion(QDataStream::Qt_4_4);
++ out << int(0);
++ out << idNextOrder;
++ out << order;
++ out.device()->seek(0);
++ out << block.size();
++ do //cut string list and send it as block of 32KB
++ {
++ QByteArray blockToSend;
++ int byteWriten;
++ blockToSend=block.left(32*1024);//32KB
++ block.remove(0,blockToSend.size());
++ byteWriten = socket.write(blockToSend);
++ }
++ while(block.size());
++}
++
+ void DesktopWindow::onPasteActivated() {
+ if(desktopHideItems_) {
+ return;
+ }
+- Fm::pasteFilesFromClipboard(path());
++ QClipboard* clipboard = QApplication::clipboard();
++ const QMimeData* data = clipboard->mimeData();
++ Fm::FilePathList paths;
++ bool isCut = false;
++
++ std::tie(paths, isCut) = Fm::parseClipboardData(*data);
++
++ if(!paths.empty()) {
++ QLocalSocket socket;
++ socket.connectToServer(QString::fromStdString("advanced-copier-"+std::to_string(getuid())));
++ socket.waitForConnected();
++ if(socket.state()==QLocalSocket::ConnectedState)
++ {
++ sendRawOrderList(QStringList() << "protocol" << "0002", socket, 1);
++ socket.waitForReadyRead();
++ socket.readAll();
++ QStringList l;
++ if(isCut) {
++ l << "mv";
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ l << "cp";
++ }
++ for(const Fm::FilePath &n : paths)
++ l << n.toString().get();
++ l << path().toString().get();
++ sendRawOrderList(l, socket, 2);
++ socket.waitForBytesWritten();
++ socket.close();
++ }
++ else
++ {
++ if(isCut) {
++ Fm::FileOperation::moveFiles(paths, path(), nullptr);
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ Fm::FileOperation::copyFiles(paths, path(), nullptr);
++ }
++ }
++ }
+ }
+
+ void DesktopWindow::onDeleteActivated() {
+diff -ur pcmanfm-qt-0.14.1/pcmanfm/mainwindow.cpp pcmanfm-qt-patched/pcmanfm/mainwindow.cpp
+--- pcmanfm-qt-0.14.1/pcmanfm/mainwindow.cpp 2019-02-23 20:16:13.000000000 -0400
++++ pcmanfm-qt-patched/pcmanfm/mainwindow.cpp 2019-12-19 17:21:07.078366000 -0400
+@@ -34,6 +34,7 @@
+ #include
+ #include
+ #include
++#include
+
+ #include "tabpage.h"
+ #include "launcher.h"
+@@ -1529,8 +1530,70 @@
+ cutFilesToClipboard(paths);
+ }
+
++void sendRawOrderListA(const QStringList & order, QLocalSocket &socket, int idNextOrder)
++{
++ QByteArray block;
++ QDataStream out(&block, QIODevice::WriteOnly);
++ out.setVersion(QDataStream::Qt_4_4);
++ out << int(0);
++ out << idNextOrder;
++ out << order;
++ out.device()->seek(0);
++ out << block.size();
++ do //cut string list and send it as block of 32KB
++ {
++ QByteArray blockToSend;
++ int byteWriten;
++ blockToSend=block.left(32*1024);//32KB
++ block.remove(0,blockToSend.size());
++ byteWriten = socket.write(blockToSend);
++ }
++ while(block.size());
++}
++
+ void MainWindow::on_actionPaste_triggered() {
+- pasteFilesFromClipboard(currentPage()->path(), this);
++ QClipboard* clipboard = QApplication::clipboard();
++ const QMimeData* data = clipboard->mimeData();
++ Fm::FilePathList paths;
++ bool isCut = false;
++
++ std::tie(paths, isCut) = parseClipboardData(*data);
++
++ if(!paths.empty()) {
++ QLocalSocket socket;
++ socket.connectToServer(QString::fromStdString("advanced-copier-"+std::to_string(getuid())));
++ socket.waitForConnected();
++ if(socket.state()==QLocalSocket::ConnectedState)
++ {
++ sendRawOrderListA(QStringList() << "protocol" << "0002", socket, 1);
++ socket.waitForReadyRead();
++ socket.readAll();
++ QStringList l;
++ if(isCut) {
++ l << "mv";
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ l << "cp";
++ }
++ for(const Fm::FilePath &n : paths)
++ l << n.toString().get();
++ l << currentPage()->path().toString().get();
++ sendRawOrderListA(l, socket, 2);
++ socket.waitForBytesWritten();
++ socket.close();
++ }
++ else
++ {
++ if(isCut) {
++ Fm::FileOperation::moveFiles(paths, currentPage()->path(), this);
++ clipboard->clear(QClipboard::Clipboard);
++ }
++ else {
++ Fm::FileOperation::copyFiles(paths, currentPage()->path(), this);
++ }
++ }
++ }
+ }
+
+ void MainWindow::on_actionDelete_triggered() {
diff -Nru ultracopier-1.6.1.3/HelpDialog.cpp ultracopier-2.2.4.4/HelpDialog.cpp
--- ultracopier-1.6.1.3/HelpDialog.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/HelpDialog.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -5,6 +5,7 @@
#include "HelpDialog.h"
#include "ProductKey.h"
+#include "FacilityEngine.h"
#include
#include
@@ -32,11 +33,7 @@
#endif // ULTRACOPIER_DEBUG
//connect the about Qt
connect(ui->pushButtonAboutQt,&QPushButton::toggled,&QApplication::aboutQt);
- #ifdef ULTRACOPIER_MODE_SUPERCOPIER
- setWindowTitle(tr("About Supercopier"));
- #else
setWindowTitle(tr("About Ultracopier"));
- #endif
#ifndef ULTRACOPIER_INTERNET_SUPPORT
ui->checkUpdate->hide();
#endif
@@ -69,9 +66,9 @@
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start");
QString text=ui->label_ultracopier->text();
if(ProductKey::productKey->isUltimate())
- text=text.replace(QStringLiteral("%1"),QStringLiteral("Ultimate %1").arg(ULTRACOPIER_VERSION));
+ text=text.replace(QStringLiteral("%1"),QStringLiteral("Ultimate %1").arg(QString::fromStdString(FacilityEngine::version())));
else
- text=text.replace(QStringLiteral("%1"),ULTRACOPIER_VERSION);
+ text=text.replace(QStringLiteral("%1"),QString::fromStdString(FacilityEngine::version()));
#ifdef ULTRACOPIER_MODE_SUPERCOPIER
text=text.replace(QStringLiteral("Ultracopier"),QStringLiteral("Supercopier"),Qt::CaseInsensitive);
#endif
diff -Nru ultracopier-1.6.1.3/HelpDialog.ui ultracopier-2.2.4.4/HelpDialog.ui
--- ultracopier-1.6.1.3/HelpDialog.ui 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/HelpDialog.ui 2010-01-01 04:00:00.000000000 +0000
@@ -91,6 +91,9 @@
Author: BRULE Herman Jacques Roger (alpha_one_x86), company: <a href="http://www.confiared.com/">confiared</a>
+
+ true
+
diff -Nru ultracopier-1.6.1.3/interface/FacilityInterface.h ultracopier-2.2.4.4/interface/FacilityInterface.h
--- ultracopier-1.6.1.3/interface/FacilityInterface.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/FacilityInterface.h 2010-01-01 04:00:00.000000000 +0000
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include "../StructEnumDefinition.h"
@@ -41,6 +42,8 @@
virtual std::string softwareName() const = 0;
/// \brief return if is ultimate
virtual bool isUltimate() const = 0;
+ /// \brief return audio if created from opus file, nullptr if failed
+ virtual void/*casted to #ifndef QAudioOutput*/* prepareOpusAudio(const std::string &file,QBuffer &buffer) const = 0;
};
#endif // FACILITY_INTERFACE_H
diff -Nru ultracopier-1.6.1.3/interface/PluginInterface_CopyEngine.h ultracopier-2.2.4.4/interface/PluginInterface_CopyEngine.h
--- ultracopier-1.6.1.3/interface/PluginInterface_CopyEngine.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/PluginInterface_CopyEngine.h 2010-01-01 04:00:00.000000000 +0000
@@ -193,6 +193,8 @@
virtual std::vector supportedProtocolsForTheDestination() const = 0;
/// \brief to get the options of the copy engine
virtual QWidget * options() = 0;
+ /// \brief to get if have pause
+ virtual bool havePause() = 0;
public slots:
/// \brief to reset the options
virtual void resetOptions() = 0;
@@ -204,7 +206,7 @@
};
#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE
-Q_DECLARE_INTERFACE(PluginInterface_CopyEngineFactory,"first-world.info.ultracopier.PluginInterface.CopyEngineFactory/1.2.4.0");
+Q_DECLARE_INTERFACE(PluginInterface_CopyEngineFactory,"first-world.info.ultracopier.PluginInterface.CopyEngineFactory/2.0.0.0");
#endif
#endif // PLUGININTERFACE_COPYENGINE_H
diff -Nru ultracopier-1.6.1.3/interface/PluginInterface_Listener.h ultracopier-2.2.4.4/interface/PluginInterface_Listener.h
--- ultracopier-1.6.1.3/interface/PluginInterface_Listener.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/PluginInterface_Listener.h 2010-01-01 04:00:00.000000000 +0000
@@ -52,7 +52,7 @@
};
#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE
-Q_DECLARE_INTERFACE(PluginInterface_Listener,"first-world.info.ultracopier.PluginInterface.Listener/1.2.4.0");
+Q_DECLARE_INTERFACE(PluginInterface_Listener,"first-world.info.ultracopier.PluginInterface.Listener/2.0.0.0");
#endif
#endif // PLUGININTERFACE_LISTENER_H
diff -Nru ultracopier-1.6.1.3/interface/PluginInterface_PluginLoader.h ultracopier-2.2.4.4/interface/PluginInterface_PluginLoader.h
--- ultracopier-1.6.1.3/interface/PluginInterface_PluginLoader.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/PluginInterface_PluginLoader.h 2010-01-01 04:00:00.000000000 +0000
@@ -35,7 +35,7 @@
};
#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE
-Q_DECLARE_INTERFACE(PluginInterface_PluginLoader,"first-world.info.ultracopier.PluginInterface.PluginLoader/1.2.4.0");
+Q_DECLARE_INTERFACE(PluginInterface_PluginLoader,"first-world.info.ultracopier.PluginInterface.PluginLoader/2.0.0.0");
#endif
#endif // PLUGININTERFACE_PLUGINLOADER_H
diff -Nru ultracopier-1.6.1.3/interface/PluginInterface_SessionLoader.h ultracopier-2.2.4.4/interface/PluginInterface_SessionLoader.h
--- ultracopier-1.6.1.3/interface/PluginInterface_SessionLoader.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/PluginInterface_SessionLoader.h 2010-01-01 04:00:00.000000000 +0000
@@ -35,7 +35,7 @@
};
#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE
-Q_DECLARE_INTERFACE(PluginInterface_SessionLoader,"first-world.info.ultracopier.PluginInterface.SessionLoader/1.2.4.0");
+Q_DECLARE_INTERFACE(PluginInterface_SessionLoader,"first-world.info.ultracopier.PluginInterface.SessionLoader/2.0.0.0");
#endif
#endif // PLUGININTERFACE_SESSIONLOADER_H
diff -Nru ultracopier-1.6.1.3/interface/PluginInterface_Themes.h ultracopier-2.2.4.4/interface/PluginInterface_Themes.h
--- ultracopier-1.6.1.3/interface/PluginInterface_Themes.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/interface/PluginInterface_Themes.h 2010-01-01 04:00:00.000000000 +0000
@@ -47,6 +47,8 @@
virtual void setGeneralProgression(const uint64_t ¤t,const uint64_t &total) = 0;
/// \brief show the file progression
virtual void setFileProgression(const std::vector &progressionList) = 0;
+ /// to get by file speed, size and ms
+ virtual void doneTime(const std::vector > &timeList) = 0;
public:
/// \brief get the widget for the copy engine
virtual QWidget * getOptionsEngineWidget() = 0;
@@ -63,6 +65,8 @@
virtual void haveExternalOrder() = 0;
/// \brief set if is in pause
virtual void isInPause(const bool &isInPause) = 0;
+ /// \brief set if is in pause
+ virtual void havePause(const bool &havePause) = 0;
// signal to implement
signals:
//set the transfer list
@@ -111,7 +115,7 @@
};
#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE
-Q_DECLARE_INTERFACE(PluginInterface_ThemesFactory,"first-world.info.ultracopier.PluginInterface.ThemesFactory/1.2.4.0");
+Q_DECLARE_INTERFACE(PluginInterface_ThemesFactory,"first-world.info.ultracopier.PluginInterface.ThemesFactory/2.0.0.0");
#endif
#endif // PLUGININTERFACE_THEMES_H
diff -Nru ultracopier-1.6.1.3/InternetUpdater.cpp ultracopier-2.2.4.4/InternetUpdater.cpp
--- ultracopier-1.6.1.3/InternetUpdater.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/InternetUpdater.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -3,6 +3,7 @@
#include "OptionEngine.h"
#include "cpp11addition.h"
#include "ProductKey.h"
+#include "Version.h"
#ifdef ULTRACOPIER_INTERNET_SUPPORT
@@ -16,9 +17,9 @@
{
connect(&newUpdateTimer,&QTimer::timeout,this,&InternetUpdater::downloadFile);
connect(&firstUpdateTimer,&QTimer::timeout,this,&InternetUpdater::downloadFile);
- newUpdateTimer.start(1000*3600);
+ newUpdateTimer.start(1000*3600*72);
firstUpdateTimer.setSingleShot(true);
- firstUpdateTimer.start(1000*60);
+ firstUpdateTimer.start(1000*600);
reply=NULL;
qnam=new QNetworkAccessManager();
}
@@ -55,9 +56,9 @@
#endif
std::string ultracopierVersion;
if(ProductKey::productKey->isUltimate())
- ultracopierVersion=name+" Ultimate/"+ULTRACOPIER_VERSION;
+ ultracopierVersion=name+" Ultimate/"+FacilityEngine::version();
else
- ultracopierVersion=name+"/"+ULTRACOPIER_VERSION;
+ ultracopierVersion=name+"/"+FacilityEngine::version();
#ifdef ULTRACOPIER_VERSION_PORTABLE
#ifdef ULTRACOPIER_PLUGIN_ALL_IN_ONE
ultracopierVersion+=" portable/all-in-one";
@@ -122,14 +123,14 @@
reply=NULL;
return;
}
- if(newVersion==ULTRACOPIER_VERSION)
+ if(newVersion.toStdString()==FacilityEngine::version())
{
reply->deleteLater();
reply=NULL;
emit noNewUpdate();
return;
}
- if(PluginsManager::compareVersion(newVersion.toStdString(),"<=",ULTRACOPIER_VERSION))
+ if(PluginsManager::compareVersion(newVersion.toStdString(),"<=",FacilityEngine::version()))
{
reply->deleteLater();
reply=NULL;
diff -Nru ultracopier-1.6.1.3/lib/qt-tar-xz/xz_dec_lzma2.c ultracopier-2.2.4.4/lib/qt-tar-xz/xz_dec_lzma2.c
--- ultracopier-1.6.1.3/lib/qt-tar-xz/xz_dec_lzma2.c 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/lib/qt-tar-xz/xz_dec_lzma2.c 2010-01-01 04:00:00.000000000 +0000
@@ -42,237 +42,237 @@
* buffer directly.
*/
struct dictionary {
- /* Beginning of the history buffer */
- uint8_t *buf;
+ /* Beginning of the history buffer */
+ uint8_t *buf;
- /* Old position in buf (before decoding more data) */
- size_t start;
+ /* Old position in buf (before decoding more data) */
+ size_t start;
- /* Position in buf */
- size_t pos;
+ /* Position in buf */
+ size_t pos;
- /*
- * How full dictionary is. This is used to detect corrupt input that
- * would read beyond the beginning of the uncompressed stream.
- */
- size_t full;
-
- /* Write limit; we don't write to buf[limit] or later bytes. */
- size_t limit;
-
- /*
- * End of the dictionary buffer. In multi-call mode, this is
- * the same as the dictionary size. In single-call mode, this
- * indicates the size of the output buffer.
- */
- size_t end;
-
- /*
- * Size of the dictionary as specified in Block Header. This is used
- * together with "full" to detect corrupt input that would make us
- * read beyond the beginning of the uncompressed stream.
- */
- uint32_t size;
-
- /*
- * Maximum allowed dictionary size in multi-call mode.
- * This is ignored in single-call mode.
- */
- uint32_t size_max;
-
- /*
- * Amount of memory currently allocated for the dictionary.
- * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
- * size_max is always the same as the allocated size.)
- */
- uint32_t allocated;
+ /*
+ * How full dictionary is. This is used to detect corrupt input that
+ * would read beyond the beginning of the uncompressed stream.
+ */
+ size_t full;
+
+ /* Write limit; we don't write to buf[limit] or later bytes. */
+ size_t limit;
+
+ /*
+ * End of the dictionary buffer. In multi-call mode, this is
+ * the same as the dictionary size. In single-call mode, this
+ * indicates the size of the output buffer.
+ */
+ size_t end;
+
+ /*
+ * Size of the dictionary as specified in Block Header. This is used
+ * together with "full" to detect corrupt input that would make us
+ * read beyond the beginning of the uncompressed stream.
+ */
+ uint32_t size;
+
+ /*
+ * Maximum allowed dictionary size in multi-call mode.
+ * This is ignored in single-call mode.
+ */
+ uint32_t size_max;
+
+ /*
+ * Amount of memory currently allocated for the dictionary.
+ * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
+ * size_max is always the same as the allocated size.)
+ */
+ uint32_t allocated;
- /* Operation mode */
- enum xz_mode mode;
+ /* Operation mode */
+ enum xz_mode mode;
};
/* Range decoder */
struct rc_dec {
- uint32_t range;
- uint32_t code;
+ uint32_t range;
+ uint32_t code;
- /*
- * Number of initializing bytes remaining to be read
- * by rc_read_init().
- */
- uint32_t init_bytes_left;
-
- /*
- * Buffer from which we read our input. It can be either
- * temp.buf or the caller-provided input buffer.
- */
- const uint8_t *in;
- size_t in_pos;
- size_t in_limit;
+ /*
+ * Number of initializing bytes remaining to be read
+ * by rc_read_init().
+ */
+ uint32_t init_bytes_left;
+
+ /*
+ * Buffer from which we read our input. It can be either
+ * temp.buf or the caller-provided input buffer.
+ */
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_limit;
};
/* Probabilities for a length decoder. */
struct lzma_len_dec {
- /* Probability of match length being at least 10 */
- uint16_t choice;
+ /* Probability of match length being at least 10 */
+ uint16_t choice;
- /* Probability of match length being at least 18 */
- uint16_t choice2;
+ /* Probability of match length being at least 18 */
+ uint16_t choice2;
- /* Probabilities for match lengths 2-9 */
- uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+ /* Probabilities for match lengths 2-9 */
+ uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
- /* Probabilities for match lengths 10-17 */
- uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+ /* Probabilities for match lengths 10-17 */
+ uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
- /* Probabilities for match lengths 18-273 */
- uint16_t high[LEN_HIGH_SYMBOLS];
+ /* Probabilities for match lengths 18-273 */
+ uint16_t high[LEN_HIGH_SYMBOLS];
};
struct lzma_dec {
- /* Distances of latest four matches */
- uint32_t rep0;
- uint32_t rep1;
- uint32_t rep2;
- uint32_t rep3;
-
- /* Types of the most recently seen LZMA symbols */
- enum lzma_state state;
-
- /*
- * Length of a match. This is updated so that dict_repeat can
- * be called again to finish repeating the whole match.
- */
- uint32_t len;
-
- /*
- * LZMA properties or related bit masks (number of literal
- * context bits, a mask dervied from the number of literal
- * position bits, and a mask dervied from the number
- * position bits)
- */
- uint32_t lc;
- uint32_t literal_pos_mask; /* (1 << lp) - 1 */
- uint32_t pos_mask; /* (1 << pb) - 1 */
-
- /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
- uint16_t is_match[STATES][POS_STATES_MAX];
-
- /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
- uint16_t is_rep[STATES];
-
- /*
- * If 0, distance of a repeated match is rep0.
- * Otherwise check is_rep1.
- */
- uint16_t is_rep0[STATES];
-
- /*
- * If 0, distance of a repeated match is rep1.
- * Otherwise check is_rep2.
- */
- uint16_t is_rep1[STATES];
-
- /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
- uint16_t is_rep2[STATES];
-
- /*
- * If 1, the repeated match has length of one byte. Otherwise
- * the length is decoded from rep_len_decoder.
- */
- uint16_t is_rep0_long[STATES][POS_STATES_MAX];
-
- /*
- * Probability tree for the highest two bits of the match
- * distance. There is a separate probability tree for match
- * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
- */
- uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
-
- /*
- * Probility trees for additional bits for match distance
- * when the distance is in the range [4, 127].
- */
- uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
-
- /*
- * Probability tree for the lowest four bits of a match
- * distance that is equal to or greater than 128.
- */
- uint16_t dist_align[ALIGN_SIZE];
+ /* Distances of latest four matches */
+ uint32_t rep0;
+ uint32_t rep1;
+ uint32_t rep2;
+ uint32_t rep3;
+
+ /* Types of the most recently seen LZMA symbols */
+ enum lzma_state state;
+
+ /*
+ * Length of a match. This is updated so that dict_repeat can
+ * be called again to finish repeating the whole match.
+ */
+ uint32_t len;
+
+ /*
+ * LZMA properties or related bit masks (number of literal
+ * context bits, a mask dervied from the number of literal
+ * position bits, and a mask dervied from the number
+ * position bits)
+ */
+ uint32_t lc;
+ uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+ uint32_t pos_mask; /* (1 << pb) - 1 */
+
+ /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+ uint16_t is_match[STATES][POS_STATES_MAX];
+
+ /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+ uint16_t is_rep[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep0.
+ * Otherwise check is_rep1.
+ */
+ uint16_t is_rep0[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep1.
+ * Otherwise check is_rep2.
+ */
+ uint16_t is_rep1[STATES];
+
+ /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+ uint16_t is_rep2[STATES];
+
+ /*
+ * If 1, the repeated match has length of one byte. Otherwise
+ * the length is decoded from rep_len_decoder.
+ */
+ uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+ /*
+ * Probability tree for the highest two bits of the match
+ * distance. There is a separate probability tree for match
+ * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ */
+ uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+ /*
+ * Probility trees for additional bits for match distance
+ * when the distance is in the range [4, 127].
+ */
+ uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+ /*
+ * Probability tree for the lowest four bits of a match
+ * distance that is equal to or greater than 128.
+ */
+ uint16_t dist_align[ALIGN_SIZE];
- /* Length of a normal match */
- struct lzma_len_dec match_len_dec;
+ /* Length of a normal match */
+ struct lzma_len_dec match_len_dec;
- /* Length of a repeated match */
- struct lzma_len_dec rep_len_dec;
+ /* Length of a repeated match */
+ struct lzma_len_dec rep_len_dec;
- /* Probabilities of literals */
- uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+ /* Probabilities of literals */
+ uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
};
struct lzma2_dec {
- /* Position in xz_dec_lzma2_run(). */
- enum lzma2_seq {
- SEQ_CONTROL,
- SEQ_UNCOMPRESSED_1,
- SEQ_UNCOMPRESSED_2,
- SEQ_COMPRESSED_0,
- SEQ_COMPRESSED_1,
- SEQ_PROPERTIES,
- SEQ_LZMA_PREPARE,
- SEQ_LZMA_RUN,
- SEQ_COPY
- } sequence;
-
- /* Next position after decoding the compressed size of the chunk. */
- enum lzma2_seq next_sequence;
-
- /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
- uint32_t uncompressed;
-
- /*
- * Compressed size of LZMA chunk or compressed/uncompressed
- * size of uncompressed chunk (64 KiB at maximum)
- */
- uint32_t compressed;
-
- /*
- * True if dictionary reset is needed. This is false before
- * the first chunk (LZMA or uncompressed).
- */
- bool need_dict_reset;
-
- /*
- * True if new LZMA properties are needed. This is false
- * before the first LZMA chunk.
- */
- bool need_props;
+ /* Position in xz_dec_lzma2_run(). */
+ enum lzma2_seq {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA_PREPARE,
+ SEQ_LZMA_RUN,
+ SEQ_COPY
+ } sequence;
+
+ /* Next position after decoding the compressed size of the chunk. */
+ enum lzma2_seq next_sequence;
+
+ /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+ uint32_t uncompressed;
+
+ /*
+ * Compressed size of LZMA chunk or compressed/uncompressed
+ * size of uncompressed chunk (64 KiB at maximum)
+ */
+ uint32_t compressed;
+
+ /*
+ * True if dictionary reset is needed. This is false before
+ * the first chunk (LZMA or uncompressed).
+ */
+ bool need_dict_reset;
+
+ /*
+ * True if new LZMA properties are needed. This is false
+ * before the first LZMA chunk.
+ */
+ bool need_props;
};
struct xz_dec_lzma2 {
- /*
- * The order below is important on x86 to reduce code size and
- * it shouldn't hurt on other platforms. Everything up to and
- * including lzma.pos_mask are in the first 128 bytes on x86-32,
- * which allows using smaller instructions to access those
- * variables. On x86-64, fewer variables fit into the first 128
- * bytes, but this is still the best order without sacrificing
- * the readability by splitting the structures.
- */
- struct rc_dec rc;
- struct dictionary dict;
- struct lzma2_dec lzma2;
- struct lzma_dec lzma;
-
- /*
- * Temporary buffer which holds small number of input bytes between
- * decoder calls. See lzma2_lzma() for details.
- */
- struct {
- uint32_t size;
- uint8_t buf[3 * LZMA_IN_REQUIRED];
- } temp;
+ /*
+ * The order below is important on x86 to reduce code size and
+ * it shouldn't hurt on other platforms. Everything up to and
+ * including lzma.pos_mask are in the first 128 bytes on x86-32,
+ * which allows using smaller instructions to access those
+ * variables. On x86-64, fewer variables fit into the first 128
+ * bytes, but this is still the best order without sacrificing
+ * the readability by splitting the structures.
+ */
+ struct rc_dec rc;
+ struct dictionary dict;
+ struct lzma2_dec lzma2;
+ struct lzma_dec lzma;
+
+ /*
+ * Temporary buffer which holds small number of input bytes between
+ * decoder calls. See lzma2_lzma() for details.
+ */
+ struct {
+ uint32_t size;
+ uint8_t buf[3 * LZMA_IN_REQUIRED];
+ } temp;
};
/**************
@@ -285,30 +285,30 @@
*/
static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b)
{
- if (DEC_IS_SINGLE(dict->mode)) {
- dict->buf = b->out + b->out_pos;
- dict->end = b->out_size - b->out_pos;
- }
-
- dict->start = 0;
- dict->pos = 0;
- dict->limit = 0;
- dict->full = 0;
+ if (DEC_IS_SINGLE(dict->mode)) {
+ dict->buf = b->out + b->out_pos;
+ dict->end = b->out_size - b->out_pos;
+ }
+
+ dict->start = 0;
+ dict->pos = 0;
+ dict->limit = 0;
+ dict->full = 0;
}
/* Set dictionary write limit */
static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max)
{
- if (dict->end - dict->pos <= out_max)
- dict->limit = dict->end;
- else
- dict->limit = dict->pos + out_max;
+ if (dict->end - dict->pos <= out_max)
+ dict->limit = dict->end;
+ else
+ dict->limit = dict->pos + out_max;
}
/* Return true if at least one byte can be written into the dictionary. */
static inline bool XZ_FUNC dict_has_space(const struct dictionary *dict)
{
- return dict->pos < dict->limit;
+ return dict->pos < dict->limit;
}
/*
@@ -318,14 +318,14 @@
* avoid writing a '\0' to the end of the destination buffer.
*/
static inline uint32_t XZ_FUNC dict_get(
- const struct dictionary *dict, uint32_t dist)
+ const struct dictionary *dict, uint32_t dist)
{
- size_t offset = dict->pos - dist - 1;
+ size_t offset = dict->pos - dist - 1;
- if (dist >= dict->pos)
- offset += dict->end;
+ if (dist >= dict->pos)
+ offset += dict->end;
- return dict->full > 0 ? dict->buf[offset] : 0;
+ return dict->full > 0 ? dict->buf[offset] : 0;
}
/*
@@ -333,10 +333,10 @@
*/
static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte)
{
- dict->buf[dict->pos++] = byte;
+ dict->buf[dict->pos++] = byte;
- if (dict->full < dict->pos)
- dict->full = dict->pos;
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
}
/*
@@ -345,70 +345,70 @@
* updated to indicate how many bytes were left to be repeated.
*/
static bool XZ_FUNC dict_repeat(
- struct dictionary *dict, uint32_t *len, uint32_t dist)
+ struct dictionary *dict, uint32_t *len, uint32_t dist)
{
- size_t back;
- uint32_t left;
+ size_t back;
+ uint32_t left;
- if (dist >= dict->full || dist >= dict->size)
- return false;
+ if (dist >= dict->full || dist >= dict->size)
+ return false;
- left = min_t(size_t, dict->limit - dict->pos, *len);
- *len -= left;
+ left = min_t(size_t, dict->limit - dict->pos, *len);
+ *len -= left;
- back = dict->pos - dist - 1;
- if (dist >= dict->pos)
- back += dict->end;
+ back = dict->pos - dist - 1;
+ if (dist >= dict->pos)
+ back += dict->end;
- do {
- dict->buf[dict->pos++] = dict->buf[back++];
- if (back == dict->end)
- back = 0;
- } while (--left > 0);
+ do {
+ dict->buf[dict->pos++] = dict->buf[back++];
+ if (back == dict->end)
+ back = 0;
+ } while (--left > 0);
- if (dict->full < dict->pos)
- dict->full = dict->pos;
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
- return true;
+ return true;
}
/* Copy uncompressed data as is from input to dictionary and output buffers. */
static void XZ_FUNC dict_uncompressed(
- struct dictionary *dict, struct xz_buf *b, uint32_t *left)
+ struct dictionary *dict, struct xz_buf *b, uint32_t *left)
{
- size_t copy_size;
+ size_t copy_size;
- while (*left > 0 && b->in_pos < b->in_size
- && b->out_pos < b->out_size) {
- copy_size = min(b->in_size - b->in_pos,
- b->out_size - b->out_pos);
- if (copy_size > dict->end - dict->pos)
- copy_size = dict->end - dict->pos;
- if (copy_size > *left)
- copy_size = *left;
+ while (*left > 0 && b->in_pos < b->in_size
+ && b->out_pos < b->out_size) {
+ copy_size = min(b->in_size - b->in_pos,
+ b->out_size - b->out_pos);
+ if (copy_size > dict->end - dict->pos)
+ copy_size = dict->end - dict->pos;
+ if (copy_size > *left)
+ copy_size = *left;
- *left -= copy_size;
+ *left -= copy_size;
- memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
- dict->pos += copy_size;
+ memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+ dict->pos += copy_size;
- if (dict->full < dict->pos)
- dict->full = dict->pos;
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
- if (DEC_IS_MULTI(dict->mode)) {
- if (dict->pos == dict->end)
- dict->pos = 0;
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
- memcpy(b->out + b->out_pos, b->in + b->in_pos,
- copy_size);
- }
+ memcpy(b->out + b->out_pos, b->in + b->in_pos,
+ copy_size);
+ }
- dict->start = dict->pos;
+ dict->start = dict->pos;
- b->out_pos += copy_size;
- b->in_pos += copy_size;
+ b->out_pos += copy_size;
+ b->in_pos += copy_size;
- }
+ }
}
/*
@@ -418,19 +418,19 @@
*/
static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b)
{
- size_t copy_size = dict->pos - dict->start;
+ size_t copy_size = dict->pos - dict->start;
- if (DEC_IS_MULTI(dict->mode)) {
- if (dict->pos == dict->end)
- dict->pos = 0;
-
- memcpy(b->out + b->out_pos, dict->buf + dict->start,
- copy_size);
- }
-
- dict->start = dict->pos;
- b->out_pos += copy_size;
- return copy_size;
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, dict->buf + dict->start,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+ b->out_pos += copy_size;
+ return copy_size;
}
/*****************
@@ -440,9 +440,9 @@
/* Reset the range decoder. */
static void XZ_FUNC rc_reset(struct rc_dec *rc)
{
- rc->range = (uint32_t)-1;
- rc->code = 0;
- rc->init_bytes_left = RC_INIT_BYTES;
+ rc->range = (uint32_t)-1;
+ rc->code = 0;
+ rc->init_bytes_left = RC_INIT_BYTES;
}
/*
@@ -451,21 +451,21 @@
*/
static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b)
{
- while (rc->init_bytes_left > 0) {
- if (b->in_pos == b->in_size)
- return false;
-
- rc->code = (rc->code << 8) + b->in[b->in_pos++];
- --rc->init_bytes_left;
- }
+ while (rc->init_bytes_left > 0) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ rc->code = (rc->code << 8) + b->in[b->in_pos++];
+ --rc->init_bytes_left;
+ }
- return true;
+ return true;
}
/* Return true if there may not be enough input for the next decoding loop. */
static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc)
{
- return rc->in_pos > rc->in_limit;
+ return rc->in_pos > rc->in_limit;
}
/*
@@ -474,16 +474,16 @@
*/
static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc)
{
- return rc->code == 0;
+ return rc->code == 0;
}
/* Read the next input byte if needed. */
static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc)
{
- if (rc->range < RC_TOP_VALUE) {
- rc->range <<= RC_SHIFT_BITS;
- rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
- }
+ if (rc->range < RC_TOP_VALUE) {
+ rc->range <<= RC_SHIFT_BITS;
+ rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+ }
}
/*
@@ -499,72 +499,72 @@
*/
static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob)
{
- uint32_t bound;
- int bit;
+ uint32_t bound;
+ int bit;
- rc_normalize(rc);
- bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
- if (rc->code < bound) {
- rc->range = bound;
- *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
- bit = 0;
- } else {
- rc->range -= bound;
- rc->code -= bound;
- *prob -= *prob >> RC_MOVE_BITS;
- bit = 1;
- }
+ rc_normalize(rc);
+ bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+ if (rc->code < bound) {
+ rc->range = bound;
+ *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+ bit = 0;
+ } else {
+ rc->range -= bound;
+ rc->code -= bound;
+ *prob -= *prob >> RC_MOVE_BITS;
+ bit = 1;
+ }
- return bit;
+ return bit;
}
/* Decode a bittree starting from the most significant bit. */
static __always_inline uint32_t XZ_FUNC rc_bittree(
- struct rc_dec *rc, uint16_t *probs, uint32_t limit)
+ struct rc_dec *rc, uint16_t *probs, uint32_t limit)
{
- uint32_t symbol = 1;
+ uint32_t symbol = 1;
- do {
- if (rc_bit(rc, &probs[symbol]))
- symbol = (symbol << 1) + 1;
- else
- symbol <<= 1;
- } while (symbol < limit);
+ do {
+ if (rc_bit(rc, &probs[symbol]))
+ symbol = (symbol << 1) + 1;
+ else
+ symbol <<= 1;
+ } while (symbol < limit);
- return symbol;
+ return symbol;
}
/* Decode a bittree starting from the least significant bit. */
static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc,
- uint16_t *probs, uint32_t *dest, uint32_t limit)
+ uint16_t *probs, uint32_t *dest, uint32_t limit)
{
- uint32_t symbol = 1;
- uint32_t i = 0;
+ uint32_t symbol = 1;
+ uint32_t i = 0;
- do {
- if (rc_bit(rc, &probs[symbol])) {
- symbol = (symbol << 1) + 1;
- *dest += 1 << i;
- } else {
- symbol <<= 1;
- }
- } while (++i < limit);
+ do {
+ if (rc_bit(rc, &probs[symbol])) {
+ symbol = (symbol << 1) + 1;
+ *dest += 1 << i;
+ } else {
+ symbol <<= 1;
+ }
+ } while (++i < limit);
}
/* Decode direct bits (fixed fifty-fifty probability) */
static inline void XZ_FUNC rc_direct(
- struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+ struct rc_dec *rc, uint32_t *dest, uint32_t limit)
{
- uint32_t mask;
+ uint32_t mask;
- do {
- rc_normalize(rc);
- rc->range >>= 1;
- rc->code -= rc->range;
- mask = (uint32_t)0 - (rc->code >> 31);
- rc->code += rc->range & mask;
- *dest = (*dest << 1) + (mask + 1);
- } while (--limit > 0);
+ do {
+ rc_normalize(rc);
+ rc->range >>= 1;
+ rc->code -= rc->range;
+ mask = (uint32_t)0 - (rc->code >> 31);
+ rc->code += rc->range & mask;
+ *dest = (*dest << 1) + (mask + 1);
+ } while (--limit > 0);
}
/********
@@ -574,114 +574,114 @@
/* Get pointer to literal coder probability array. */
static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s)
{
- uint32_t prev_byte = dict_get(&s->dict, 0);
- uint32_t low = prev_byte >> (8 - s->lzma.lc);
- uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
- return s->lzma.literal[low + high];
+ uint32_t prev_byte = dict_get(&s->dict, 0);
+ uint32_t low = prev_byte >> (8 - s->lzma.lc);
+ uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+ return s->lzma.literal[low + high];
}
/* Decode a literal (one 8-bit byte) */
static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s)
{
- uint16_t *probs;
- uint32_t symbol;
- uint32_t match_byte;
- uint32_t match_bit;
- uint32_t offset;
- uint32_t i;
-
- probs = lzma_literal_probs(s);
-
- if (lzma_state_is_literal(s->lzma.state)) {
- symbol = rc_bittree(&s->rc, probs, 0x100);
- } else {
- symbol = 1;
- match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
- offset = 0x100;
-
- do {
- match_bit = match_byte & offset;
- match_byte <<= 1;
- i = offset + match_bit + symbol;
-
- if (rc_bit(&s->rc, &probs[i])) {
- symbol = (symbol << 1) + 1;
- offset &= match_bit;
- } else {
- symbol <<= 1;
- offset &= ~match_bit;
- }
- } while (symbol < 0x100);
- }
+ uint16_t *probs;
+ uint32_t symbol;
+ uint32_t match_byte;
+ uint32_t match_bit;
+ uint32_t offset;
+ uint32_t i;
+
+ probs = lzma_literal_probs(s);
+
+ if (lzma_state_is_literal(s->lzma.state)) {
+ symbol = rc_bittree(&s->rc, probs, 0x100);
+ } else {
+ symbol = 1;
+ match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+ offset = 0x100;
+
+ do {
+ match_bit = match_byte & offset;
+ match_byte <<= 1;
+ i = offset + match_bit + symbol;
+
+ if (rc_bit(&s->rc, &probs[i])) {
+ symbol = (symbol << 1) + 1;
+ offset &= match_bit;
+ } else {
+ symbol <<= 1;
+ offset &= ~match_bit;
+ }
+ } while (symbol < 0x100);
+ }
- dict_put(&s->dict, (uint8_t)symbol);
- lzma_state_literal(&s->lzma.state);
+ dict_put(&s->dict, (uint8_t)symbol);
+ lzma_state_literal(&s->lzma.state);
}
/* Decode the length of the match into s->lzma.len. */
static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
- uint32_t pos_state)
+ uint32_t pos_state)
{
- uint16_t *probs;
- uint32_t limit;
+ uint16_t *probs;
+ uint32_t limit;
- if (!rc_bit(&s->rc, &l->choice)) {
- probs = l->low[pos_state];
- limit = LEN_LOW_SYMBOLS;
- s->lzma.len = MATCH_LEN_MIN;
- } else {
- if (!rc_bit(&s->rc, &l->choice2)) {
- probs = l->mid[pos_state];
- limit = LEN_MID_SYMBOLS;
- s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
- } else {
- probs = l->high;
- limit = LEN_HIGH_SYMBOLS;
- s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
- + LEN_MID_SYMBOLS;
- }
- }
+ if (!rc_bit(&s->rc, &l->choice)) {
+ probs = l->low[pos_state];
+ limit = LEN_LOW_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN;
+ } else {
+ if (!rc_bit(&s->rc, &l->choice2)) {
+ probs = l->mid[pos_state];
+ limit = LEN_MID_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+ } else {
+ probs = l->high;
+ limit = LEN_HIGH_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+ + LEN_MID_SYMBOLS;
+ }
+ }
- s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+ s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
}
/* Decode a match. The distance will be stored in s->lzma.rep0. */
static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
{
- uint16_t *probs;
- uint32_t dist_slot;
- uint32_t limit;
-
- lzma_state_match(&s->lzma.state);
-
- s->lzma.rep3 = s->lzma.rep2;
- s->lzma.rep2 = s->lzma.rep1;
- s->lzma.rep1 = s->lzma.rep0;
-
- lzma_len(s, &s->lzma.match_len_dec, pos_state);
-
- probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
- dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
-
- if (dist_slot < DIST_MODEL_START) {
- s->lzma.rep0 = dist_slot;
- } else {
- limit = (dist_slot >> 1) - 1;
- s->lzma.rep0 = 2 + (dist_slot & 1);
-
- if (dist_slot < DIST_MODEL_END) {
- s->lzma.rep0 <<= limit;
- probs = s->lzma.dist_special + s->lzma.rep0
- - dist_slot - 1;
- rc_bittree_reverse(&s->rc, probs,
- &s->lzma.rep0, limit);
- } else {
- rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
- s->lzma.rep0 <<= ALIGN_BITS;
- rc_bittree_reverse(&s->rc, s->lzma.dist_align,
- &s->lzma.rep0, ALIGN_BITS);
- }
- }
+ uint16_t *probs;
+ uint32_t dist_slot;
+ uint32_t limit;
+
+ lzma_state_match(&s->lzma.state);
+
+ s->lzma.rep3 = s->lzma.rep2;
+ s->lzma.rep2 = s->lzma.rep1;
+ s->lzma.rep1 = s->lzma.rep0;
+
+ lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+ probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+ dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+ if (dist_slot < DIST_MODEL_START) {
+ s->lzma.rep0 = dist_slot;
+ } else {
+ limit = (dist_slot >> 1) - 1;
+ s->lzma.rep0 = 2 + (dist_slot & 1);
+
+ if (dist_slot < DIST_MODEL_END) {
+ s->lzma.rep0 <<= limit;
+ probs = s->lzma.dist_special + s->lzma.rep0
+ - dist_slot - 1;
+ rc_bittree_reverse(&s->rc, probs,
+ &s->lzma.rep0, limit);
+ } else {
+ rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+ s->lzma.rep0 <<= ALIGN_BITS;
+ rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+ &s->lzma.rep0, ALIGN_BITS);
+ }
+ }
}
/*
@@ -690,77 +690,77 @@
*/
static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
{
- uint32_t tmp;
+ uint32_t tmp;
- if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
- if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
- s->lzma.state][pos_state])) {
- lzma_state_short_rep(&s->lzma.state);
- s->lzma.len = 1;
- return;
- }
- } else {
- if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
- tmp = s->lzma.rep1;
- } else {
- if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
- tmp = s->lzma.rep2;
- } else {
- tmp = s->lzma.rep3;
- s->lzma.rep3 = s->lzma.rep2;
- }
-
- s->lzma.rep2 = s->lzma.rep1;
- }
-
- s->lzma.rep1 = s->lzma.rep0;
- s->lzma.rep0 = tmp;
- }
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+ s->lzma.state][pos_state])) {
+ lzma_state_short_rep(&s->lzma.state);
+ s->lzma.len = 1;
+ return;
+ }
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+ tmp = s->lzma.rep1;
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+ tmp = s->lzma.rep2;
+ } else {
+ tmp = s->lzma.rep3;
+ s->lzma.rep3 = s->lzma.rep2;
+ }
+
+ s->lzma.rep2 = s->lzma.rep1;
+ }
+
+ s->lzma.rep1 = s->lzma.rep0;
+ s->lzma.rep0 = tmp;
+ }
- lzma_state_long_rep(&s->lzma.state);
- lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+ lzma_state_long_rep(&s->lzma.state);
+ lzma_len(s, &s->lzma.rep_len_dec, pos_state);
}
/* LZMA decoder core */
static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s)
{
- uint32_t pos_state;
+ uint32_t pos_state;
- /*
- * If the dictionary was reached during the previous call, try to
- * finish the possibly pending repeat in the dictionary.
- */
- if (dict_has_space(&s->dict) && s->lzma.len > 0)
- dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
-
- /*
- * Decode more LZMA symbols. One iteration may consume up to
- * LZMA_IN_REQUIRED - 1 bytes.
- */
- while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
- pos_state = s->dict.pos & s->lzma.pos_mask;
-
- if (!rc_bit(&s->rc, &s->lzma.is_match[
- s->lzma.state][pos_state])) {
- lzma_literal(s);
- } else {
- if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
- lzma_rep_match(s, pos_state);
- else
- lzma_match(s, pos_state);
-
- if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
- return false;
- }
- }
-
- /*
- * Having the range decoder always normalized when we are outside
- * this function makes it easier to correctly handle end of the chunk.
- */
- rc_normalize(&s->rc);
+ /*
+ * If the dictionary was reached during the previous call, try to
+ * finish the possibly pending repeat in the dictionary.
+ */
+ if (dict_has_space(&s->dict) && s->lzma.len > 0)
+ dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+ /*
+ * Decode more LZMA symbols. One iteration may consume up to
+ * LZMA_IN_REQUIRED - 1 bytes.
+ */
+ while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+ pos_state = s->dict.pos & s->lzma.pos_mask;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_match[
+ s->lzma.state][pos_state])) {
+ lzma_literal(s);
+ } else {
+ if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+ lzma_rep_match(s, pos_state);
+ else
+ lzma_match(s, pos_state);
+
+ if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+ return false;
+ }
+ }
+
+ /*
+ * Having the range decoder always normalized when we are outside
+ * this function makes it easier to correctly handle end of the chunk.
+ */
+ rc_normalize(&s->rc);
- return true;
+ return true;
}
/*
@@ -769,29 +769,29 @@
*/
static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s)
{
- uint16_t *probs;
- size_t i;
+ uint16_t *probs;
+ size_t i;
- s->lzma.state = STATE_LIT_LIT;
- s->lzma.rep0 = 0;
- s->lzma.rep1 = 0;
- s->lzma.rep2 = 0;
- s->lzma.rep3 = 0;
-
- /*
- * All probabilities are initialized to the same value. This hack
- * makes the code smaller by avoiding a separate loop for each
- * probability array.
- *
- * This could be optimized so that only that part of literal
- * probabilities that are actually required. In the common case
- * we would write 12 KiB less.
- */
- probs = s->lzma.is_match[0];
- for (i = 0; i < PROBS_TOTAL; ++i)
- probs[i] = RC_BIT_MODEL_TOTAL / 2;
+ s->lzma.state = STATE_LIT_LIT;
+ s->lzma.rep0 = 0;
+ s->lzma.rep1 = 0;
+ s->lzma.rep2 = 0;
+ s->lzma.rep3 = 0;
+
+ /*
+ * All probabilities are initialized to the same value. This hack
+ * makes the code smaller by avoiding a separate loop for each
+ * probability array.
+ *
+ * This could be optimized so that only that part of literal
+ * probabilities that are actually required. In the common case
+ * we would write 12 KiB less.
+ */
+ probs = s->lzma.is_match[0];
+ for (i = 0; i < PROBS_TOTAL; ++i)
+ probs[i] = RC_BIT_MODEL_TOTAL / 2;
- rc_reset(&s->rc);
+ rc_reset(&s->rc);
}
/*
@@ -801,33 +801,33 @@
*/
static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
{
- if (props > (4 * 5 + 4) * 9 + 8)
- return false;
+ if (props > (4 * 5 + 4) * 9 + 8)
+ return false;
- s->lzma.pos_mask = 0;
- while (props >= 9 * 5) {
- props -= 9 * 5;
- ++s->lzma.pos_mask;
- }
+ s->lzma.pos_mask = 0;
+ while (props >= 9 * 5) {
+ props -= 9 * 5;
+ ++s->lzma.pos_mask;
+ }
- s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+ s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
- s->lzma.literal_pos_mask = 0;
- while (props >= 9) {
- props -= 9;
- ++s->lzma.literal_pos_mask;
- }
+ s->lzma.literal_pos_mask = 0;
+ while (props >= 9) {
+ props -= 9;
+ ++s->lzma.literal_pos_mask;
+ }
- s->lzma.lc = props;
+ s->lzma.lc = props;
- if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
- return false;
+ if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+ return false;
- s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+ s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
- lzma_reset(s);
+ lzma_reset(s);
- return true;
+ return true;
}
/*********
@@ -848,83 +848,83 @@
*/
static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
{
- size_t in_avail;
- uint32_t tmp;
+ size_t in_avail;
+ uint32_t tmp;
- in_avail = b->in_size - b->in_pos;
- if (s->temp.size > 0 || s->lzma2.compressed == 0) {
- tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
- if (tmp > s->lzma2.compressed - s->temp.size)
- tmp = s->lzma2.compressed - s->temp.size;
- if (tmp > in_avail)
- tmp = in_avail;
-
- memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
-
- if (s->temp.size + tmp == s->lzma2.compressed) {
- memzero(s->temp.buf + s->temp.size + tmp,
- sizeof(s->temp.buf)
- - s->temp.size - tmp);
- s->rc.in_limit = s->temp.size + tmp;
- } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
- s->temp.size += tmp;
- b->in_pos += tmp;
- return true;
- } else {
- s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
- }
-
- s->rc.in = s->temp.buf;
- s->rc.in_pos = 0;
-
- if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
- return false;
-
- s->lzma2.compressed -= s->rc.in_pos;
-
- if (s->rc.in_pos < s->temp.size) {
- s->temp.size -= s->rc.in_pos;
- memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
- s->temp.size);
- return true;
- }
-
- b->in_pos += s->rc.in_pos - s->temp.size;
- s->temp.size = 0;
- }
-
- in_avail = b->in_size - b->in_pos;
- if (in_avail >= LZMA_IN_REQUIRED) {
- s->rc.in = b->in;
- s->rc.in_pos = b->in_pos;
-
- if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
- s->rc.in_limit = b->in_pos + s->lzma2.compressed;
- else
- s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
-
- if (!lzma_main(s))
- return false;
-
- in_avail = s->rc.in_pos - b->in_pos;
- if (in_avail > s->lzma2.compressed)
- return false;
-
- s->lzma2.compressed -= in_avail;
- b->in_pos = s->rc.in_pos;
- }
-
- in_avail = b->in_size - b->in_pos;
- if (in_avail < LZMA_IN_REQUIRED) {
- if (in_avail > s->lzma2.compressed)
- in_avail = s->lzma2.compressed;
-
- memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
- s->temp.size = in_avail;
- b->in_pos += in_avail;
- }
+ in_avail = b->in_size - b->in_pos;
+ if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+ tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+ if (tmp > s->lzma2.compressed - s->temp.size)
+ tmp = s->lzma2.compressed - s->temp.size;
+ if (tmp > in_avail)
+ tmp = in_avail;
+
+ memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+ if (s->temp.size + tmp == s->lzma2.compressed) {
+ memzero(s->temp.buf + s->temp.size + tmp,
+ sizeof(s->temp.buf)
+ - s->temp.size - tmp);
+ s->rc.in_limit = s->temp.size + tmp;
+ } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+ s->temp.size += tmp;
+ b->in_pos += tmp;
+ return true;
+ } else {
+ s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+ }
+
+ s->rc.in = s->temp.buf;
+ s->rc.in_pos = 0;
+
+ if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+ return false;
+
+ s->lzma2.compressed -= s->rc.in_pos;
+
+ if (s->rc.in_pos < s->temp.size) {
+ s->temp.size -= s->rc.in_pos;
+ memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+ s->temp.size);
+ return true;
+ }
+
+ b->in_pos += s->rc.in_pos - s->temp.size;
+ s->temp.size = 0;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail >= LZMA_IN_REQUIRED) {
+ s->rc.in = b->in;
+ s->rc.in_pos = b->in_pos;
+
+ if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+ s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+ else
+ s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+ if (!lzma_main(s))
+ return false;
+
+ in_avail = s->rc.in_pos - b->in_pos;
+ if (in_avail > s->lzma2.compressed)
+ return false;
+
+ s->lzma2.compressed -= in_avail;
+ b->in_pos = s->rc.in_pos;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail < LZMA_IN_REQUIRED) {
+ if (in_avail > s->lzma2.compressed)
+ in_avail = s->lzma2.compressed;
+
+ memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+ s->temp.size = in_avail;
+ b->in_pos += in_avail;
+ }
- return true;
+ return true;
}
/*
@@ -932,244 +932,248 @@
* decoding or copying of uncompressed chunks to other functions.
*/
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run(
- struct xz_dec_lzma2 *s, struct xz_buf *b)
+ struct xz_dec_lzma2 *s, struct xz_buf *b)
{
- uint32_t tmp;
+ uint32_t tmp;
- while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
- switch (s->lzma2.sequence) {
- case SEQ_CONTROL:
- /*
- * LZMA2 control byte
- *
- * Exact values:
- * 0x00 End marker
- * 0x01 Dictionary reset followed by
- * an uncompressed chunk
- * 0x02 Uncompressed chunk (no dictionary reset)
- *
- * Highest three bits (s->control & 0xE0):
- * 0xE0 Dictionary reset, new properties and state
- * reset, followed by LZMA compressed chunk
- * 0xC0 New properties and state reset, followed
- * by LZMA compressed chunk (no dictionary
- * reset)
- * 0xA0 State reset using old properties,
- * followed by LZMA compressed chunk (no
- * dictionary reset)
- * 0x80 LZMA chunk (no dictionary or state reset)
- *
- * For LZMA compressed chunks, the lowest five bits
- * (s->control & 1F) are the highest bits of the
- * uncompressed size (bits 16-20).
- *
- * A new LZMA2 stream must begin with a dictionary
- * reset. The first LZMA chunk must set new
- * properties and reset the LZMA state.
- *
- * Values that don't match anything described above
- * are invalid and we return XZ_DATA_ERROR.
- */
- tmp = b->in[b->in_pos++];
-
- if (tmp >= 0xE0 || tmp == 0x01) {
- s->lzma2.need_props = true;
- s->lzma2.need_dict_reset = false;
- dict_reset(&s->dict, b);
- } else if (s->lzma2.need_dict_reset) {
- return XZ_DATA_ERROR;
- }
-
- if (tmp >= 0x80) {
- s->lzma2.uncompressed = (tmp & 0x1F) << 16;
- s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
-
- if (tmp >= 0xC0) {
- /*
- * When there are new properties,
- * state reset is done at
- * SEQ_PROPERTIES.
- */
- s->lzma2.need_props = false;
- s->lzma2.next_sequence
- = SEQ_PROPERTIES;
-
- } else if (s->lzma2.need_props) {
- return XZ_DATA_ERROR;
-
- } else {
- s->lzma2.next_sequence
- = SEQ_LZMA_PREPARE;
- if (tmp >= 0xA0)
- lzma_reset(s);
- }
- } else {
- if (tmp == 0x00)
- return XZ_STREAM_END;
-
- if (tmp > 0x02)
- return XZ_DATA_ERROR;
-
- s->lzma2.sequence = SEQ_COMPRESSED_0;
- s->lzma2.next_sequence = SEQ_COPY;
- }
-
- break;
-
- case SEQ_UNCOMPRESSED_1:
- s->lzma2.uncompressed
- += (uint32_t)b->in[b->in_pos++] << 8;
- s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
- break;
-
- case SEQ_UNCOMPRESSED_2:
- s->lzma2.uncompressed
- += (uint32_t)b->in[b->in_pos++] + 1;
- s->lzma2.sequence = SEQ_COMPRESSED_0;
- break;
-
- case SEQ_COMPRESSED_0:
- s->lzma2.compressed
- = (uint32_t)b->in[b->in_pos++] << 8;
- s->lzma2.sequence = SEQ_COMPRESSED_1;
- break;
-
- case SEQ_COMPRESSED_1:
- s->lzma2.compressed
- += (uint32_t)b->in[b->in_pos++] + 1;
- s->lzma2.sequence = s->lzma2.next_sequence;
- break;
-
- case SEQ_PROPERTIES:
- if (!lzma_props(s, b->in[b->in_pos++]))
- return XZ_DATA_ERROR;
-
- s->lzma2.sequence = SEQ_LZMA_PREPARE;
-
- case SEQ_LZMA_PREPARE:
- if (s->lzma2.compressed < RC_INIT_BYTES)
- return XZ_DATA_ERROR;
-
- if (!rc_read_init(&s->rc, b))
- return XZ_OK;
-
- s->lzma2.compressed -= RC_INIT_BYTES;
- s->lzma2.sequence = SEQ_LZMA_RUN;
-
- case SEQ_LZMA_RUN:
- /*
- * Set dictionary limit to indicate how much we want
- * to be encoded at maximum. Decode new data into the
- * dictionary. Flush the new data from dictionary to
- * b->out. Check if we finished decoding this chunk.
- * In case the dictionary got full but we didn't fill
- * the output buffer yet, we may run this loop
- * multiple times without changing s->lzma2.sequence.
- */
- dict_limit(&s->dict, min_t(size_t,
- b->out_size - b->out_pos,
- s->lzma2.uncompressed));
- if (!lzma2_lzma(s, b))
- return XZ_DATA_ERROR;
-
- s->lzma2.uncompressed -= dict_flush(&s->dict, b);
-
- if (s->lzma2.uncompressed == 0) {
- if (s->lzma2.compressed > 0 || s->lzma.len > 0
- || !rc_is_finished(&s->rc))
- return XZ_DATA_ERROR;
-
- rc_reset(&s->rc);
- s->lzma2.sequence = SEQ_CONTROL;
-
- } else if (b->out_pos == b->out_size
- || (b->in_pos == b->in_size
- && s->temp.size
- < s->lzma2.compressed)) {
- return XZ_OK;
- }
-
- break;
-
- case SEQ_COPY:
- dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
- if (s->lzma2.compressed > 0)
- return XZ_OK;
-
- s->lzma2.sequence = SEQ_CONTROL;
- break;
- }
- }
+ while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+ switch (s->lzma2.sequence) {
+ case SEQ_CONTROL:
+ /*
+ * LZMA2 control byte
+ *
+ * Exact values:
+ * 0x00 End marker
+ * 0x01 Dictionary reset followed by
+ * an uncompressed chunk
+ * 0x02 Uncompressed chunk (no dictionary reset)
+ *
+ * Highest three bits (s->control & 0xE0):
+ * 0xE0 Dictionary reset, new properties and state
+ * reset, followed by LZMA compressed chunk
+ * 0xC0 New properties and state reset, followed
+ * by LZMA compressed chunk (no dictionary
+ * reset)
+ * 0xA0 State reset using old properties,
+ * followed by LZMA compressed chunk (no
+ * dictionary reset)
+ * 0x80 LZMA chunk (no dictionary or state reset)
+ *
+ * For LZMA compressed chunks, the lowest five bits
+ * (s->control & 1F) are the highest bits of the
+ * uncompressed size (bits 16-20).
+ *
+ * A new LZMA2 stream must begin with a dictionary
+ * reset. The first LZMA chunk must set new
+ * properties and reset the LZMA state.
+ *
+ * Values that don't match anything described above
+ * are invalid and we return XZ_DATA_ERROR.
+ */
+ tmp = b->in[b->in_pos++];
+
+ if (tmp >= 0xE0 || tmp == 0x01) {
+ s->lzma2.need_props = true;
+ s->lzma2.need_dict_reset = false;
+ dict_reset(&s->dict, b);
+ } else if (s->lzma2.need_dict_reset) {
+ return XZ_DATA_ERROR;
+ }
+
+ if (tmp >= 0x80) {
+ s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+ if (tmp >= 0xC0) {
+ /*
+ * When there are new properties,
+ * state reset is done at
+ * SEQ_PROPERTIES.
+ */
+ s->lzma2.need_props = false;
+ s->lzma2.next_sequence
+ = SEQ_PROPERTIES;
+
+ } else if (s->lzma2.need_props) {
+ return XZ_DATA_ERROR;
+
+ } else {
+ s->lzma2.next_sequence
+ = SEQ_LZMA_PREPARE;
+ if (tmp >= 0xA0)
+ lzma_reset(s);
+ }
+ } else {
+ if (tmp == 0x00)
+ return XZ_STREAM_END;
+
+ if (tmp > 0x02)
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ s->lzma2.next_sequence = SEQ_COPY;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_1:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ break;
+
+ case SEQ_COMPRESSED_0:
+ s->lzma2.compressed
+ = (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ s->lzma2.compressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = s->lzma2.next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (!lzma_props(s, b->in[b->in_pos++]))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_LZMA_PREPARE;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_LZMA_PREPARE:
+ if (s->lzma2.compressed < RC_INIT_BYTES)
+ return XZ_DATA_ERROR;
+
+ if (!rc_read_init(&s->rc, b))
+ return XZ_OK;
+
+ s->lzma2.compressed -= RC_INIT_BYTES;
+ s->lzma2.sequence = SEQ_LZMA_RUN;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_LZMA_RUN:
+ /*
+ * Set dictionary limit to indicate how much we want
+ * to be encoded at maximum. Decode new data into the
+ * dictionary. Flush the new data from dictionary to
+ * b->out. Check if we finished decoding this chunk.
+ * In case the dictionary got full but we didn't fill
+ * the output buffer yet, we may run this loop
+ * multiple times without changing s->lzma2.sequence.
+ */
+ dict_limit(&s->dict, min_t(size_t,
+ b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
+ if (!lzma2_lzma(s, b))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+ if (s->lzma2.uncompressed == 0) {
+ if (s->lzma2.compressed > 0 || s->lzma.len > 0
+ || !rc_is_finished(&s->rc))
+ return XZ_DATA_ERROR;
+
+ rc_reset(&s->rc);
+ s->lzma2.sequence = SEQ_CONTROL;
+
+ } else if (b->out_pos == b->out_size
+ || (b->in_pos == b->in_size
+ && s->temp.size
+ < s->lzma2.compressed)) {
+ return XZ_OK;
+ }
+
+ break;
+
+ case SEQ_COPY:
+ dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+ if (s->lzma2.compressed > 0)
+ return XZ_OK;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ break;
+ }
+ }
- return XZ_OK;
+ return XZ_OK;
}
XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(
- enum xz_mode mode, uint32_t dict_max)
+ enum xz_mode mode, uint32_t dict_max)
{
- struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (s == NULL)
- return NULL;
-
- s->dict.mode = mode;
- s->dict.size_max = dict_max;
-
- if (DEC_IS_PREALLOC(mode)) {
- s->dict.buf = vmalloc(dict_max);
- if (s->dict.buf == NULL) {
- kfree(s);
- return NULL;
- }
- } else if (DEC_IS_DYNALLOC(mode)) {
- s->dict.buf = NULL;
- s->dict.allocated = 0;
- }
+ struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->dict.mode = mode;
+ s->dict.size_max = dict_max;
+
+ if (DEC_IS_PREALLOC(mode)) {
+ s->dict.buf = vmalloc(dict_max);
+ if (s->dict.buf == NULL) {
+ kfree(s);
+ return NULL;
+ }
+ } else if (DEC_IS_DYNALLOC(mode)) {
+ s->dict.buf = NULL;
+ s->dict.allocated = 0;
+ }
- return s;
+ return s;
}
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset(
- struct xz_dec_lzma2 *s, uint8_t props)
+ struct xz_dec_lzma2 *s, uint8_t props)
{
- /* This limits dictionary size to 3 GiB to keep parsing simpler. */
- if (props > 39)
- return XZ_OPTIONS_ERROR;
+ /* This limits dictionary size to 3 GiB to keep parsing simpler. */
+ if (props > 39)
+ return XZ_OPTIONS_ERROR;
- s->dict.size = 2 + (props & 1);
- s->dict.size <<= (props >> 1) + 11;
+ s->dict.size = 2 + (props & 1);
+ s->dict.size <<= (props >> 1) + 11;
- if (DEC_IS_MULTI(s->dict.mode)) {
- if (s->dict.size > s->dict.size_max)
- return XZ_MEMLIMIT_ERROR;
+ if (DEC_IS_MULTI(s->dict.mode)) {
+ if (s->dict.size > s->dict.size_max)
+ return XZ_MEMLIMIT_ERROR;
- s->dict.end = s->dict.size;
+ s->dict.end = s->dict.size;
- if (DEC_IS_DYNALLOC(s->dict.mode)) {
- if (s->dict.allocated < s->dict.size) {
- vfree(s->dict.buf);
- s->dict.buf = vmalloc(s->dict.size);
- if (s->dict.buf == NULL) {
- s->dict.allocated = 0;
- return XZ_MEM_ERROR;
- }
- }
- }
- }
+ if (DEC_IS_DYNALLOC(s->dict.mode)) {
+ if (s->dict.allocated < s->dict.size) {
+ vfree(s->dict.buf);
+ s->dict.buf = vmalloc(s->dict.size);
+ if (s->dict.buf == NULL) {
+ s->dict.allocated = 0;
+ return XZ_MEM_ERROR;
+ }
+ }
+ }
+ }
- s->lzma.len = 0;
+ s->lzma.len = 0;
- s->lzma2.sequence = SEQ_CONTROL;
- s->lzma2.need_dict_reset = true;
+ s->lzma2.sequence = SEQ_CONTROL;
+ s->lzma2.need_dict_reset = true;
- s->temp.size = 0;
+ s->temp.size = 0;
- return XZ_OK;
+ return XZ_OK;
}
XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
{
- if (DEC_IS_MULTI(s->dict.mode))
- vfree(s->dict.buf);
+ if (DEC_IS_MULTI(s->dict.mode))
+ vfree(s->dict.buf);
- kfree(s);
+ kfree(s);
}
diff -Nru ultracopier-1.6.1.3/lib/qt-tar-xz/xz_dec_stream.c ultracopier-2.2.4.4/lib/qt-tar-xz/xz_dec_stream.c
--- ultracopier-1.6.1.3/lib/qt-tar-xz/xz_dec_stream.c 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/lib/qt-tar-xz/xz_dec_stream.c 2010-01-01 04:00:00.000000000 +0000
@@ -12,139 +12,139 @@
/* Hash used to validate the Index field */
struct xz_dec_hash {
- vli_type unpadded;
- vli_type uncompressed;
- uint32_t crc32;
+ vli_type unpadded;
+ vli_type uncompressed;
+ uint32_t crc32;
};
struct xz_dec {
- /* Position in dec_main() */
- enum {
- SEQ_STREAM_HEADER,
- SEQ_BLOCK_START,
- SEQ_BLOCK_HEADER,
- SEQ_BLOCK_UNCOMPRESS,
- SEQ_BLOCK_PADDING,
- SEQ_BLOCK_CHECK,
- SEQ_INDEX,
- SEQ_INDEX_PADDING,
- SEQ_INDEX_CRC32,
- SEQ_STREAM_FOOTER
- } sequence;
-
- /* Position in variable-length integers and Check fields */
- uint32_t pos;
-
- /* Variable-length integer decoded by dec_vli() */
- vli_type vli;
-
- /* Saved in_pos and out_pos */
- size_t in_start;
- size_t out_start;
-
- /* CRC32 value in Block or Index */
- uint32_t crc32;
-
- /* Type of the integrity check calculated from uncompressed data */
- enum xz_check check_type;
-
- /* Operation mode */
- enum xz_mode mode;
-
- /*
- * True if the next call to xz_dec_run() is allowed to return
- * XZ_BUF_ERROR.
- */
- bool allow_buf_error;
-
- /* Information stored in Block Header */
- struct {
- /*
- * Value stored in the Compressed Size field, or
- * VLI_UNKNOWN if Compressed Size is not present.
- */
- vli_type compressed;
-
- /*
- * Value stored in the Uncompressed Size field, or
- * VLI_UNKNOWN if Uncompressed Size is not present.
- */
- vli_type uncompressed;
-
- /* Size of the Block Header field */
- uint32_t size;
- } block_header;
-
- /* Information collected when decoding Blocks */
- struct {
- /* Observed compressed size of the current Block */
- vli_type compressed;
-
- /* Observed uncompressed size of the current Block */
- vli_type uncompressed;
-
- /* Number of Blocks decoded so far */
- vli_type count;
-
- /*
- * Hash calculated from the Block sizes. This is used to
- * validate the Index field.
- */
- struct xz_dec_hash hash;
- } block;
-
- /* Variables needed when verifying the Index field */
- struct {
- /* Position in dec_index() */
- enum {
- SEQ_INDEX_COUNT,
- SEQ_INDEX_UNPADDED,
- SEQ_INDEX_UNCOMPRESSED
- } sequence;
-
- /* Size of the Index in bytes */
- vli_type size;
-
- /* Number of Records (matches block.count in valid files) */
- vli_type count;
-
- /*
- * Hash calculated from the Records (matches block.hash in
- * valid files).
- */
- struct xz_dec_hash hash;
- } index;
-
- /*
- * Temporary buffer needed to hold Stream Header, Block Header,
- * and Stream Footer. The Block Header is the biggest (1 KiB)
- * so we reserve space according to that. buf[] has to be aligned
- * to a multiple of four bytes; the size_t variables before it
- * should guarantee this.
- */
- struct {
- size_t pos;
- size_t size;
- uint8_t buf[1024];
- } temp;
+ /* Position in dec_main() */
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_START,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK_UNCOMPRESS,
+ SEQ_BLOCK_PADDING,
+ SEQ_BLOCK_CHECK,
+ SEQ_INDEX,
+ SEQ_INDEX_PADDING,
+ SEQ_INDEX_CRC32,
+ SEQ_STREAM_FOOTER
+ } sequence;
+
+ /* Position in variable-length integers and Check fields */
+ uint32_t pos;
+
+ /* Variable-length integer decoded by dec_vli() */
+ vli_type vli;
+
+ /* Saved in_pos and out_pos */
+ size_t in_start;
+ size_t out_start;
+
+ /* CRC32 value in Block or Index */
+ uint32_t crc32;
+
+ /* Type of the integrity check calculated from uncompressed data */
+ enum xz_check check_type;
+
+ /* Operation mode */
+ enum xz_mode mode;
+
+ /*
+ * True if the next call to xz_dec_run() is allowed to return
+ * XZ_BUF_ERROR.
+ */
+ bool allow_buf_error;
+
+ /* Information stored in Block Header */
+ struct {
+ /*
+ * Value stored in the Compressed Size field, or
+ * VLI_UNKNOWN if Compressed Size is not present.
+ */
+ vli_type compressed;
+
+ /*
+ * Value stored in the Uncompressed Size field, or
+ * VLI_UNKNOWN if Uncompressed Size is not present.
+ */
+ vli_type uncompressed;
+
+ /* Size of the Block Header field */
+ uint32_t size;
+ } block_header;
+
+ /* Information collected when decoding Blocks */
+ struct {
+ /* Observed compressed size of the current Block */
+ vli_type compressed;
+
+ /* Observed uncompressed size of the current Block */
+ vli_type uncompressed;
+
+ /* Number of Blocks decoded so far */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Block sizes. This is used to
+ * validate the Index field.
+ */
+ struct xz_dec_hash hash;
+ } block;
+
+ /* Variables needed when verifying the Index field */
+ struct {
+ /* Position in dec_index() */
+ enum {
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_UNPADDED,
+ SEQ_INDEX_UNCOMPRESSED
+ } sequence;
+
+ /* Size of the Index in bytes */
+ vli_type size;
+
+ /* Number of Records (matches block.count in valid files) */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Records (matches block.hash in
+ * valid files).
+ */
+ struct xz_dec_hash hash;
+ } index;
+
+ /*
+ * Temporary buffer needed to hold Stream Header, Block Header,
+ * and Stream Footer. The Block Header is the biggest (1 KiB)
+ * so we reserve space according to that. buf[] has to be aligned
+ * to a multiple of four bytes; the size_t variables before it
+ * should guarantee this.
+ */
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buf[1024];
+ } temp;
- struct xz_dec_lzma2 *lzma2;
+ struct xz_dec_lzma2 *lzma2;
#ifdef XZ_DEC_BCJ
- struct xz_dec_bcj *bcj;
- bool bcj_active;
+ struct xz_dec_bcj *bcj;
+ bool bcj_active;
#endif
};
#ifdef XZ_DEC_ANY_CHECK
/* Sizes of the Check field with different Check IDs */
static const uint8_t check_sizes[16] = {
- 0,
- 4, 4, 4,
- 8, 8, 8,
- 16, 16, 16,
- 32, 32, 32,
- 64, 64, 64
+ 0,
+ 4, 4, 4,
+ 8, 8, 8,
+ 16, 16, 16,
+ 32, 32, 32,
+ 64, 64, 64
};
#endif
@@ -156,51 +156,51 @@
*/
static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b)
{
- size_t copy_size = min_t(size_t,
- b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+ size_t copy_size = min_t(size_t,
+ b->in_size - b->in_pos, s->temp.size - s->temp.pos);
- memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
- b->in_pos += copy_size;
- s->temp.pos += copy_size;
-
- if (s->temp.pos == s->temp.size) {
- s->temp.pos = 0;
- return true;
- }
+ memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+ b->in_pos += copy_size;
+ s->temp.pos += copy_size;
+
+ if (s->temp.pos == s->temp.size) {
+ s->temp.pos = 0;
+ return true;
+ }
- return false;
+ return false;
}
/* Decode a variable-length integer (little-endian base-128 encoding) */
static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s,
- const uint8_t *in, size_t *in_pos, size_t in_size)
+ const uint8_t *in, size_t *in_pos, size_t in_size)
{
- uint8_t byte;
+ uint8_t byte;
- if (s->pos == 0)
- s->vli = 0;
+ if (s->pos == 0)
+ s->vli = 0;
- while (*in_pos < in_size) {
- byte = in[*in_pos];
- ++*in_pos;
+ while (*in_pos < in_size) {
+ byte = in[*in_pos];
+ ++*in_pos;
- s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+ s->vli |= (vli_type)(byte & 0x7F) << s->pos;
- if ((byte & 0x80) == 0) {
- /* Don't allow non-minimal encodings. */
- if (byte == 0 && s->pos != 0)
- return XZ_DATA_ERROR;
+ if ((byte & 0x80) == 0) {
+ /* Don't allow non-minimal encodings. */
+ if (byte == 0 && s->pos != 0)
+ return XZ_DATA_ERROR;
- s->pos = 0;
- return XZ_STREAM_END;
- }
+ s->pos = 0;
+ return XZ_STREAM_END;
+ }
- s->pos += 7;
- if (s->pos == 7 * VLI_BYTES_MAX)
- return XZ_DATA_ERROR;
- }
+ s->pos += 7;
+ if (s->pos == 7 * VLI_BYTES_MAX)
+ return XZ_DATA_ERROR;
+ }
- return XZ_OK;
+ return XZ_OK;
}
/*
@@ -217,72 +217,72 @@
*/
static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b)
{
- enum xz_ret ret;
+ enum xz_ret ret;
- s->in_start = b->in_pos;
- s->out_start = b->out_pos;
+ s->in_start = b->in_pos;
+ s->out_start = b->out_pos;
#ifdef XZ_DEC_BCJ
- if (s->bcj_active)
- ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
- else
-#endif
- ret = xz_dec_lzma2_run(s->lzma2, b);
-
- s->block.compressed += b->in_pos - s->in_start;
- s->block.uncompressed += b->out_pos - s->out_start;
-
- /*
- * There is no need to separately check for VLI_UNKNOWN, since
- * the observed sizes are always smaller than VLI_UNKNOWN.
- */
- if (s->block.compressed > s->block_header.compressed
- || s->block.uncompressed
- > s->block_header.uncompressed)
- return XZ_DATA_ERROR;
-
- if (s->check_type == XZ_CHECK_CRC32)
- s->crc32 = xz_crc32(b->out + s->out_start,
- b->out_pos - s->out_start, s->crc32);
-
- if (ret == XZ_STREAM_END) {
- if (s->block_header.compressed != VLI_UNKNOWN
- && s->block_header.compressed
- != s->block.compressed)
- return XZ_DATA_ERROR;
-
- if (s->block_header.uncompressed != VLI_UNKNOWN
- && s->block_header.uncompressed
- != s->block.uncompressed)
- return XZ_DATA_ERROR;
+ if (s->bcj_active)
+ ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+ else
+#endif
+ ret = xz_dec_lzma2_run(s->lzma2, b);
+
+ s->block.compressed += b->in_pos - s->in_start;
+ s->block.uncompressed += b->out_pos - s->out_start;
+
+ /*
+ * There is no need to separately check for VLI_UNKNOWN, since
+ * the observed sizes are always smaller than VLI_UNKNOWN.
+ */
+ if (s->block.compressed > s->block_header.compressed
+ || s->block.uncompressed
+ > s->block_header.uncompressed)
+ return XZ_DATA_ERROR;
+
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->crc32 = xz_crc32(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc32);
+
+ if (ret == XZ_STREAM_END) {
+ if (s->block_header.compressed != VLI_UNKNOWN
+ && s->block_header.compressed
+ != s->block.compressed)
+ return XZ_DATA_ERROR;
+
+ if (s->block_header.uncompressed != VLI_UNKNOWN
+ && s->block_header.uncompressed
+ != s->block.uncompressed)
+ return XZ_DATA_ERROR;
- s->block.hash.unpadded += s->block_header.size
- + s->block.compressed;
+ s->block.hash.unpadded += s->block_header.size
+ + s->block.compressed;
#ifdef XZ_DEC_ANY_CHECK
- s->block.hash.unpadded += check_sizes[s->check_type];
+ s->block.hash.unpadded += check_sizes[s->check_type];
#else
- if (s->check_type == XZ_CHECK_CRC32)
- s->block.hash.unpadded += 4;
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->block.hash.unpadded += 4;
#endif
- s->block.hash.uncompressed += s->block.uncompressed;
- s->block.hash.crc32 = xz_crc32(
- (const uint8_t *)&s->block.hash,
- sizeof(s->block.hash), s->block.hash.crc32);
+ s->block.hash.uncompressed += s->block.uncompressed;
+ s->block.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->block.hash,
+ sizeof(s->block.hash), s->block.hash.crc32);
- ++s->block.count;
- }
+ ++s->block.count;
+ }
- return ret;
+ return ret;
}
/* Update the Index size and the CRC32 value. */
static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b)
{
- size_t in_used = b->in_pos - s->in_start;
- s->index.size += in_used;
- s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
+ size_t in_used = b->in_pos - s->in_start;
+ s->index.size += in_used;
+ s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32);
}
/*
@@ -295,48 +295,48 @@
*/
static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b)
{
- enum xz_ret ret;
+ enum xz_ret ret;
- do {
- ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
- if (ret != XZ_STREAM_END) {
- index_update(s, b);
- return ret;
- }
-
- switch (s->index.sequence) {
- case SEQ_INDEX_COUNT:
- s->index.count = s->vli;
-
- /*
- * Validate that the Number of Records field
- * indicates the same number of Records as
- * there were Blocks in the Stream.
- */
- if (s->index.count != s->block.count)
- return XZ_DATA_ERROR;
-
- s->index.sequence = SEQ_INDEX_UNPADDED;
- break;
-
- case SEQ_INDEX_UNPADDED:
- s->index.hash.unpadded += s->vli;
- s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
- break;
-
- case SEQ_INDEX_UNCOMPRESSED:
- s->index.hash.uncompressed += s->vli;
- s->index.hash.crc32 = xz_crc32(
- (const uint8_t *)&s->index.hash,
- sizeof(s->index.hash),
- s->index.hash.crc32);
- --s->index.count;
- s->index.sequence = SEQ_INDEX_UNPADDED;
- break;
- }
- } while (s->index.count > 0);
+ do {
+ ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+ if (ret != XZ_STREAM_END) {
+ index_update(s, b);
+ return ret;
+ }
+
+ switch (s->index.sequence) {
+ case SEQ_INDEX_COUNT:
+ s->index.count = s->vli;
+
+ /*
+ * Validate that the Number of Records field
+ * indicates the same number of Records as
+ * there were Blocks in the Stream.
+ */
+ if (s->index.count != s->block.count)
+ return XZ_DATA_ERROR;
+
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+
+ case SEQ_INDEX_UNPADDED:
+ s->index.hash.unpadded += s->vli;
+ s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+ break;
+
+ case SEQ_INDEX_UNCOMPRESSED:
+ s->index.hash.uncompressed += s->vli;
+ s->index.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->index.hash,
+ sizeof(s->index.hash),
+ s->index.hash.crc32);
+ --s->index.count;
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+ }
+ } while (s->index.count > 0);
- return XZ_STREAM_END;
+ return XZ_STREAM_END;
}
/*
@@ -345,21 +345,21 @@
*/
static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b)
{
- do {
- if (b->in_pos == b->in_size)
- return XZ_OK;
+ do {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
- if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
- return XZ_DATA_ERROR;
+ if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++])
+ return XZ_DATA_ERROR;
- s->pos += 8;
+ s->pos += 8;
- } while (s->pos < 32);
+ } while (s->pos < 32);
- s->crc32 = 0;
- s->pos = 0;
+ s->crc32 = 0;
+ s->pos = 0;
- return XZ_STREAM_END;
+ return XZ_STREAM_END;
}
#ifdef XZ_DEC_ANY_CHECK
@@ -369,341 +369,354 @@
*/
static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b)
{
- while (s->pos < check_sizes[s->check_type]) {
- if (b->in_pos == b->in_size)
- return false;
+ while (s->pos < check_sizes[s->check_type]) {
+ if (b->in_pos == b->in_size)
+ return false;
- ++b->in_pos;
- ++s->pos;
- }
+ ++b->in_pos;
+ ++s->pos;
+ }
- s->pos = 0;
+ s->pos = 0;
- return true;
+ return true;
}
#endif
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s)
{
- if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
- return XZ_FORMAT_ERROR;
+ if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+ return XZ_FORMAT_ERROR;
- if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
- != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
- return XZ_DATA_ERROR;
-
- if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
- return XZ_OPTIONS_ERROR;
-
- /*
- * Of integrity checks, we support only none (Check ID = 0) and
- * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
- * we will accept other check types too, but then the check won't
- * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
- */
- s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+ if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+ != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+ return XZ_OPTIONS_ERROR;
+
+ /*
+ * Of integrity checks, we support only none (Check ID = 0) and
+ * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
+ * we will accept other check types too, but then the check won't
+ * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
+ */
+ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
#ifdef XZ_DEC_ANY_CHECK
- if (s->check_type > XZ_CHECK_MAX)
- return XZ_OPTIONS_ERROR;
+ if (s->check_type > XZ_CHECK_MAX)
+ return XZ_OPTIONS_ERROR;
- if (s->check_type > XZ_CHECK_CRC32)
- return XZ_UNSUPPORTED_CHECK;
+ if (s->check_type > XZ_CHECK_CRC32)
+ return XZ_UNSUPPORTED_CHECK;
#else
- if (s->check_type > XZ_CHECK_CRC32)
- return XZ_OPTIONS_ERROR;
+ if (s->check_type > XZ_CHECK_CRC32)
+ return XZ_OPTIONS_ERROR;
#endif
- return XZ_OK;
+ return XZ_OK;
}
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s)
{
- if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
- return XZ_DATA_ERROR;
+ if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+ return XZ_DATA_ERROR;
- if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
- return XZ_DATA_ERROR;
+ if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+ return XZ_DATA_ERROR;
- /*
- * Validate Backward Size. Note that we never added the size of the
- * Index CRC32 field to s->index.size, thus we use s->index.size / 4
- * instead of s->index.size / 4 - 1.
- */
- if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
- return XZ_DATA_ERROR;
-
- if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
- return XZ_DATA_ERROR;
-
- /*
- * Use XZ_STREAM_END instead of XZ_OK to be more convenient
- * for the caller.
- */
- return XZ_STREAM_END;
+ /*
+ * Validate Backward Size. Note that we never added the size of the
+ * Index CRC32 field to s->index.size, thus we use s->index.size / 4
+ * instead of s->index.size / 4 - 1.
+ */
+ if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
+ return XZ_DATA_ERROR;
+
+ /*
+ * Use XZ_STREAM_END instead of XZ_OK to be more convenient
+ * for the caller.
+ */
+ return XZ_STREAM_END;
}
/* Decode the Block Header and initialize the filter chain. */
static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s)
{
- enum xz_ret ret;
+ enum xz_ret ret;
- /*
- * Validate the CRC32. We know that the temp buffer is at least
- * eight bytes so this is safe.
- */
- s->temp.size -= 4;
- if (xz_crc32(s->temp.buf, s->temp.size, 0)
- != get_le32(s->temp.buf + s->temp.size))
- return XZ_DATA_ERROR;
-
- s->temp.pos = 2;
-
- /*
- * Catch unsupported Block Flags. We support only one or two filters
- * in the chain, so we catch that with the same test.
- */
+ /*
+ * Validate the CRC32. We know that the temp buffer is at least
+ * eight bytes so this is safe.
+ */
+ s->temp.size -= 4;
+ if (xz_crc32(s->temp.buf, s->temp.size, 0)
+ != get_le32(s->temp.buf + s->temp.size))
+ return XZ_DATA_ERROR;
+
+ s->temp.pos = 2;
+
+ /*
+ * Catch unsupported Block Flags. We support only one or two filters
+ * in the chain, so we catch that with the same test.
+ */
#ifdef XZ_DEC_BCJ
- if (s->temp.buf[1] & 0x3E)
+ if (s->temp.buf[1] & 0x3E)
#else
- if (s->temp.buf[1] & 0x3F)
+ if (s->temp.buf[1] & 0x3F)
#endif
- return XZ_OPTIONS_ERROR;
+ return XZ_OPTIONS_ERROR;
- /* Compressed Size */
- if (s->temp.buf[1] & 0x40) {
- if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
- != XZ_STREAM_END)
- return XZ_DATA_ERROR;
-
- s->block_header.compressed = s->vli;
- } else {
- s->block_header.compressed = VLI_UNKNOWN;
- }
-
- /* Uncompressed Size */
- if (s->temp.buf[1] & 0x80) {
- if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
- != XZ_STREAM_END)
- return XZ_DATA_ERROR;
-
- s->block_header.uncompressed = s->vli;
- } else {
- s->block_header.uncompressed = VLI_UNKNOWN;
- }
+ /* Compressed Size */
+ if (s->temp.buf[1] & 0x40) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.compressed = s->vli;
+ } else {
+ s->block_header.compressed = VLI_UNKNOWN;
+ }
+
+ /* Uncompressed Size */
+ if (s->temp.buf[1] & 0x80) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.uncompressed = s->vli;
+ } else {
+ s->block_header.uncompressed = VLI_UNKNOWN;
+ }
#ifdef XZ_DEC_BCJ
- /* If there are two filters, the first one must be a BCJ filter. */
- s->bcj_active = s->temp.buf[1] & 0x01;
- if (s->bcj_active) {
- if (s->temp.size - s->temp.pos < 2)
- return XZ_OPTIONS_ERROR;
-
- ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
- if (ret != XZ_OK)
- return ret;
-
- /*
- * We don't support custom start offset,
- * so Size of Properties must be zero.
- */
- if (s->temp.buf[s->temp.pos++] != 0x00)
- return XZ_OPTIONS_ERROR;
- }
-#endif
-
- /* Valid Filter Flags always take at least two bytes. */
- if (s->temp.size - s->temp.pos < 2)
- return XZ_DATA_ERROR;
-
- /* Filter ID = LZMA2 */
- if (s->temp.buf[s->temp.pos++] != 0x21)
- return XZ_OPTIONS_ERROR;
-
- /* Size of Properties = 1-byte Filter Properties */
- if (s->temp.buf[s->temp.pos++] != 0x01)
- return XZ_OPTIONS_ERROR;
-
- /* Filter Properties contains LZMA2 dictionary size. */
- if (s->temp.size - s->temp.pos < 1)
- return XZ_DATA_ERROR;
-
- ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
- if (ret != XZ_OK)
- return ret;
-
- /* The rest must be Header Padding. */
- while (s->temp.pos < s->temp.size)
- if (s->temp.buf[s->temp.pos++] != 0x00)
- return XZ_OPTIONS_ERROR;
-
- s->temp.pos = 0;
- s->block.compressed = 0;
- s->block.uncompressed = 0;
+ /* If there are two filters, the first one must be a BCJ filter. */
+ s->bcj_active = s->temp.buf[1] & 0x01;
+ if (s->bcj_active) {
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_OPTIONS_ERROR;
+
+ ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /*
+ * We don't support custom start offset,
+ * so Size of Properties must be zero.
+ */
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+ }
+#endif
+
+ /* Valid Filter Flags always take at least two bytes. */
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_DATA_ERROR;
+
+ /* Filter ID = LZMA2 */
+ if (s->temp.buf[s->temp.pos++] != 0x21)
+ return XZ_OPTIONS_ERROR;
+
+ /* Size of Properties = 1-byte Filter Properties */
+ if (s->temp.buf[s->temp.pos++] != 0x01)
+ return XZ_OPTIONS_ERROR;
+
+ /* Filter Properties contains LZMA2 dictionary size. */
+ if (s->temp.size - s->temp.pos < 1)
+ return XZ_DATA_ERROR;
+
+ ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /* The rest must be Header Padding. */
+ while (s->temp.pos < s->temp.size)
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+
+ s->temp.pos = 0;
+ s->block.compressed = 0;
+ s->block.uncompressed = 0;
- return XZ_OK;
+ return XZ_OK;
}
static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b)
{
- enum xz_ret ret;
+ enum xz_ret ret;
- /*
- * Store the start position for the case when we are in the middle
- * of the Index field.
- */
- s->in_start = b->in_pos;
-
- while (true) {
- switch (s->sequence) {
- case SEQ_STREAM_HEADER:
- /*
- * Stream Header is copied to s->temp, and then
- * decoded from there. This way if the caller
- * gives us only little input at a time, we can
- * still keep the Stream Header decoding code
- * simple. Similar approach is used in many places
- * in this file.
- */
- if (!fill_temp(s, b))
- return XZ_OK;
-
- /*
- * If dec_stream_header() returns
- * XZ_UNSUPPORTED_CHECK, it is still possible
- * to continue decoding if working in multi-call
- * mode. Thus, update s->sequence before calling
- * dec_stream_header().
- */
- s->sequence = SEQ_BLOCK_START;
-
- ret = dec_stream_header(s);
- if (ret != XZ_OK)
- return ret;
-
- case SEQ_BLOCK_START:
- /* We need one byte of input to continue. */
- if (b->in_pos == b->in_size)
- return XZ_OK;
-
- /* See if this is the beginning of the Index field. */
- if (b->in[b->in_pos] == 0) {
- s->in_start = b->in_pos++;
- s->sequence = SEQ_INDEX;
- break;
- }
-
- /*
- * Calculate the size of the Block Header and
- * prepare to decode it.
- */
- s->block_header.size
- = ((uint32_t)b->in[b->in_pos] + 1) * 4;
-
- s->temp.size = s->block_header.size;
- s->temp.pos = 0;
- s->sequence = SEQ_BLOCK_HEADER;
-
- case SEQ_BLOCK_HEADER:
- if (!fill_temp(s, b))
- return XZ_OK;
-
- ret = dec_block_header(s);
- if (ret != XZ_OK)
- return ret;
-
- s->sequence = SEQ_BLOCK_UNCOMPRESS;
-
- case SEQ_BLOCK_UNCOMPRESS:
- ret = dec_block(s, b);
- if (ret != XZ_STREAM_END)
- return ret;
-
- s->sequence = SEQ_BLOCK_PADDING;
-
- case SEQ_BLOCK_PADDING:
- /*
- * Size of Compressed Data + Block Padding
- * must be a multiple of four. We don't need
- * s->block.compressed for anything else
- * anymore, so we use it here to test the size
- * of the Block Padding field.
- */
- while (s->block.compressed & 3) {
- if (b->in_pos == b->in_size)
- return XZ_OK;
-
- if (b->in[b->in_pos++] != 0)
- return XZ_DATA_ERROR;
-
- ++s->block.compressed;
- }
-
- s->sequence = SEQ_BLOCK_CHECK;
-
- case SEQ_BLOCK_CHECK:
- if (s->check_type == XZ_CHECK_CRC32) {
- ret = crc32_validate(s, b);
- if (ret != XZ_STREAM_END)
- return ret;
- }
+ /*
+ * Store the start position for the case when we are in the middle
+ * of the Index field.
+ */
+ s->in_start = b->in_pos;
+
+ while (true) {
+ switch (s->sequence) {
+ case SEQ_STREAM_HEADER:
+ /*
+ * Stream Header is copied to s->temp, and then
+ * decoded from there. This way if the caller
+ * gives us only little input at a time, we can
+ * still keep the Stream Header decoding code
+ * simple. Similar approach is used in many places
+ * in this file.
+ */
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ /*
+ * If dec_stream_header() returns
+ * XZ_UNSUPPORTED_CHECK, it is still possible
+ * to continue decoding if working in multi-call
+ * mode. Thus, update s->sequence before calling
+ * dec_stream_header().
+ */
+ s->sequence = SEQ_BLOCK_START;
+
+ ret = dec_stream_header(s);
+ if (ret != XZ_OK)
+ return ret;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_BLOCK_START:
+ /* We need one byte of input to continue. */
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ /* See if this is the beginning of the Index field. */
+ if (b->in[b->in_pos] == 0) {
+ s->in_start = b->in_pos++;
+ s->sequence = SEQ_INDEX;
+ break;
+ }
+
+ /*
+ * Calculate the size of the Block Header and
+ * prepare to decode it.
+ */
+ s->block_header.size
+ = ((uint32_t)b->in[b->in_pos] + 1) * 4;
+
+ s->temp.size = s->block_header.size;
+ s->temp.pos = 0;
+ s->sequence = SEQ_BLOCK_HEADER;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_BLOCK_HEADER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ ret = dec_block_header(s);
+ if (ret != XZ_OK)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_UNCOMPRESS;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_BLOCK_UNCOMPRESS:
+ ret = dec_block(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_PADDING;
+
+ case SEQ_BLOCK_PADDING:
+ /*
+ * Size of Compressed Data + Block Padding
+ * must be a multiple of four. We don't need
+ * s->block.compressed for anything else
+ * anymore, so we use it here to test the size
+ * of the Block Padding field.
+ */
+ while (s->block.compressed & 3) {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+
+ ++s->block.compressed;
+ }
+
+ s->sequence = SEQ_BLOCK_CHECK;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_BLOCK_CHECK:
+ if (s->check_type == XZ_CHECK_CRC32) {
+ ret = crc32_validate(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+ }
#ifdef XZ_DEC_ANY_CHECK
- else if (!check_skip(s, b)) {
- return XZ_OK;
- }
-#endif
-
- s->sequence = SEQ_BLOCK_START;
- break;
-
- case SEQ_INDEX:
- ret = dec_index(s, b);
- if (ret != XZ_STREAM_END)
- return ret;
-
- s->sequence = SEQ_INDEX_PADDING;
-
- case SEQ_INDEX_PADDING:
- while ((s->index.size + (b->in_pos - s->in_start))
- & 3) {
- if (b->in_pos == b->in_size) {
- index_update(s, b);
- return XZ_OK;
- }
-
- if (b->in[b->in_pos++] != 0)
- return XZ_DATA_ERROR;
- }
-
- /* Finish the CRC32 value and Index size. */
- index_update(s, b);
-
- /* Compare the hashes to validate the Index field. */
- if (!memeq(&s->block.hash, &s->index.hash,
- sizeof(s->block.hash)))
- return XZ_DATA_ERROR;
-
- s->sequence = SEQ_INDEX_CRC32;
-
- case SEQ_INDEX_CRC32:
- ret = crc32_validate(s, b);
- if (ret != XZ_STREAM_END)
- return ret;
-
- s->temp.size = STREAM_HEADER_SIZE;
- s->sequence = SEQ_STREAM_FOOTER;
-
- case SEQ_STREAM_FOOTER:
- if (!fill_temp(s, b))
- return XZ_OK;
-
- return dec_stream_footer(s);
- }
- }
+ else if (!check_skip(s, b)) {
+ return XZ_OK;
+ }
+#endif
+
+ s->sequence = SEQ_BLOCK_START;
+ break;
+ case SEQ_INDEX:
+ ret = dec_index(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_INDEX_PADDING;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_INDEX_PADDING:
+ while ((s->index.size + (b->in_pos - s->in_start))
+ & 3) {
+ if (b->in_pos == b->in_size) {
+ index_update(s, b);
+ return XZ_OK;
+ }
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+ }
+
+ /* Finish the CRC32 value and Index size. */
+ index_update(s, b);
+
+ /* Compare the hashes to validate the Index field. */
+ if (!memeq(&s->block.hash, &s->index.hash,
+ sizeof(s->block.hash)))
+ return XZ_DATA_ERROR;
+
+ s->sequence = SEQ_INDEX_CRC32;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_INDEX_CRC32:
+ ret = crc32_validate(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->temp.size = STREAM_HEADER_SIZE;
+ s->sequence = SEQ_STREAM_FOOTER;
+ #ifndef __clang__
+ __attribute__ ((fallthrough));
+ #endif
+ case SEQ_STREAM_FOOTER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ return dec_stream_footer(s);
+ }
+ }
- /* Never reached */
+ /* Never reached */
}
/*
@@ -733,90 +746,90 @@
*/
XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b)
{
- size_t in_start;
- size_t out_start;
- enum xz_ret ret;
-
- if (DEC_IS_SINGLE(s->mode))
- xz_dec_reset(s);
-
- in_start = b->in_pos;
- out_start = b->out_pos;
- ret = dec_main(s, b);
-
- if (DEC_IS_SINGLE(s->mode)) {
- if (ret == XZ_OK)
- ret = b->in_pos == b->in_size
- ? XZ_DATA_ERROR : XZ_BUF_ERROR;
-
- if (ret != XZ_STREAM_END) {
- b->in_pos = in_start;
- b->out_pos = out_start;
- }
-
- } else if (ret == XZ_OK && in_start == b->in_pos
- && out_start == b->out_pos) {
- if (s->allow_buf_error)
- ret = XZ_BUF_ERROR;
-
- s->allow_buf_error = true;
- } else {
- s->allow_buf_error = false;
- }
+ size_t in_start;
+ size_t out_start;
+ enum xz_ret ret;
+
+ if (DEC_IS_SINGLE(s->mode))
+ xz_dec_reset(s);
+
+ in_start = b->in_pos;
+ out_start = b->out_pos;
+ ret = dec_main(s, b);
+
+ if (DEC_IS_SINGLE(s->mode)) {
+ if (ret == XZ_OK)
+ ret = b->in_pos == b->in_size
+ ? XZ_DATA_ERROR : XZ_BUF_ERROR;
+
+ if (ret != XZ_STREAM_END) {
+ b->in_pos = in_start;
+ b->out_pos = out_start;
+ }
+
+ } else if (ret == XZ_OK && in_start == b->in_pos
+ && out_start == b->out_pos) {
+ if (s->allow_buf_error)
+ ret = XZ_BUF_ERROR;
+
+ s->allow_buf_error = true;
+ } else {
+ s->allow_buf_error = false;
+ }
- return ret;
+ return ret;
}
XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(
- enum xz_mode mode, uint32_t dict_max)
+ enum xz_mode mode, uint32_t dict_max)
{
- struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (s == NULL)
- return NULL;
+ struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
- s->mode = mode;
+ s->mode = mode;
#ifdef XZ_DEC_BCJ
- s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
- if (s->bcj == NULL)
- goto error_bcj;
+ s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
+ if (s->bcj == NULL)
+ goto error_bcj;
#endif
- s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
- if (s->lzma2 == NULL)
- goto error_lzma2;
+ s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
+ if (s->lzma2 == NULL)
+ goto error_lzma2;
- xz_dec_reset(s);
- return s;
+ xz_dec_reset(s);
+ return s;
error_lzma2:
#ifdef XZ_DEC_BCJ
- xz_dec_bcj_end(s->bcj);
+ xz_dec_bcj_end(s->bcj);
error_bcj:
#endif
- kfree(s);
- return NULL;
+ kfree(s);
+ return NULL;
}
XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s)
{
- s->sequence = SEQ_STREAM_HEADER;
- s->allow_buf_error = false;
- s->pos = 0;
- s->crc32 = 0;
- memzero(&s->block, sizeof(s->block));
- memzero(&s->index, sizeof(s->index));
- s->temp.pos = 0;
- s->temp.size = STREAM_HEADER_SIZE;
+ s->sequence = SEQ_STREAM_HEADER;
+ s->allow_buf_error = false;
+ s->pos = 0;
+ s->crc32 = 0;
+ memzero(&s->block, sizeof(s->block));
+ memzero(&s->index, sizeof(s->index));
+ s->temp.pos = 0;
+ s->temp.size = STREAM_HEADER_SIZE;
}
XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s)
{
- if (s != NULL) {
- xz_dec_lzma2_end(s->lzma2);
+ if (s != NULL) {
+ xz_dec_lzma2_end(s->lzma2);
#ifdef XZ_DEC_BCJ
- xz_dec_bcj_end(s->bcj);
+ xz_dec_bcj_end(s->bcj);
#endif
- kfree(s);
- }
+ kfree(s);
+ }
}
diff -Nru ultracopier-1.6.1.3/libfm-qt-ultracopier/libfm-qt-ultracopier.pro ultracopier-2.2.4.4/libfm-qt-ultracopier/libfm-qt-ultracopier.pro
--- ultracopier-1.6.1.3/libfm-qt-ultracopier/libfm-qt-ultracopier.pro 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libfm-qt-ultracopier/libfm-qt-ultracopier.pro 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,14 @@
+CONFIG += c++11
+
+TEMPLATE = lib
+QT += network widgets
+TARGET = $$qtLibraryTarget(fm-qt)
+LIBS += -Llibfm-qt
+INCLUDEPATH += /usr/include/glib-2.0/ /usr/lib64/glib-2.0/include/
+DEFINES += QT_NO_KEYWORDS
+
+HEADERS += \
+ utilities.h
+
+SOURCES += \
+ utilities.cpp
diff -Nru ultracopier-1.6.1.3/libfm-qt-ultracopier/README ultracopier-2.2.4.4/libfm-qt-ultracopier/README
--- ultracopier-1.6.1.3/libfm-qt-ultracopier/README 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libfm-qt-ultracopier/README 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1 @@
+LD_LIBRARY_PATH=/home/user/Desktop/ultracopier/sources/build-libfm-qt-ultracopier-Desktop-Debug/libfm-qt.so.1.0.0 pcmanfm-qt
diff -Nru ultracopier-1.6.1.3/libfm-qt-ultracopier/utilities.cpp ultracopier-2.2.4.4/libfm-qt-ultracopier/utilities.cpp
--- ultracopier-1.6.1.3/libfm-qt-ultracopier/utilities.cpp 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libfm-qt-ultracopier/utilities.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,89 @@
+#include "utilities.h"
+#include
+#include
+#include
+#include
+#include
+
+namespace Fm {
+
+void sendRawOrderList(const QStringList & order, QLocalSocket &socket, int idNextOrder)
+{
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_4);
+ out << int(0);
+ out << idNextOrder;
+ out << order;
+ out.device()->seek(0);
+ out << block.size();
+ do //cut string list and send it as block of 32KB
+ {
+ QByteArray blockToSend;
+ int byteWriten;
+ blockToSend=block.left(32*1024);//32KB
+ block.remove(0,blockToSend.size());
+ byteWriten = socket.write(blockToSend);
+ }
+ while(block.size());
+}
+
+void pasteFilesFromClipboard(const Fm::FilePath& destPath, QWidget* parent) {
+ //https://gist.github.com/mooware/1174572
+ typedef std::pair (*methodType)(const QMimeData& data);
+
+ static methodType origMethod = 0;
+
+ // use the mangled method name here. RTLD_NEXT means something like
+ // "search this symbol in any libraries loaded after the current one".
+ void *tmpPtr = dlsym(RTLD_NEXT, "pasteFilesFromClipboard");
+
+ // not even reinterpret_cast can convert between void* and a method ptr,
+ // so i'm doing the worst hack i've ever seen.
+ memcpy(&origMethod, &tmpPtr, sizeof(tmpPtr));
+
+ QClipboard* clipboard = QApplication::clipboard();
+ const QMimeData* data = clipboard->mimeData();
+ Fm::FilePathList paths;
+ bool isCut = false;
+
+ std::tie(paths, isCut) = (*origMethod)(*data);
+
+ if(!paths.empty()) {
+ QLocalSocket socket;
+ socket.connectToServer(QString::fromStdString("advanced-copier-"+std::to_string(getuid())));
+ socket.waitForConnected();
+ if(socket.state()==QLocalSocket::ConnectedState)
+ {
+ sendRawOrderList(QStringList() << "protocol" << "0002", socket, 1);
+ socket.waitForReadyRead();
+ socket.readAll();
+ QStringList l;
+ if(isCut) {
+ l << "mv";
+ clipboard->clear(QClipboard::Clipboard);
+ }
+ else {
+ l << "cp";
+ }
+ for(const FilePath &n : paths)
+ l << n.toString().get();
+ l << destPath.toString().get();
+ sendRawOrderList(l, socket, 2);
+ socket.waitForBytesWritten();
+ socket.close();
+ }
+ else
+ {
+ if(isCut) {
+ FileOperation::moveFiles(paths, destPath, parent);
+ clipboard->clear(QClipboard::Clipboard);
+ }
+ else {
+ FileOperation::copyFiles(paths, destPath, parent);
+ }
+ }
+ }
+}
+
+} // namespace Fm
diff -Nru ultracopier-1.6.1.3/libfm-qt-ultracopier/utilities.h ultracopier-2.2.4.4/libfm-qt-ultracopier/utilities.h
--- ultracopier-1.6.1.3/libfm-qt-ultracopier/utilities.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libfm-qt-ultracopier/utilities.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,21 @@
+#include
+#include
+#include
+
+#include
+#include
+
+#ifndef FM_UTILITIESUC_H
+#define FM_UTILITIESUC_H
+
+namespace Fm {
+
+__attribute__((visibility("default"))) void pasteFilesFromClipboard(const Fm::FilePath& destPath, QWidget* parent);
+
+std::string pathSocket();
+char * toHex(const char *str);
+void sendRawOrderList(const QStringList & order, QLocalSocket &socket);
+
+}
+
+#endif // FM_UTILITIESUC_H
diff -Nru ultracopier-1.6.1.3/libogg/bitwise.c ultracopier-2.2.4.4/libogg/bitwise.c
--- ultracopier-1.6.1.3/libogg/bitwise.c 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libogg/bitwise.c 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,1088 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: packing variable sized words into an octet stream
+ last mod: $Id$
+
+ ********************************************************************/
+
+/* We're 'LSb' endian; if we write a word but read individual bits,
+ then we'll read the lsb first */
+
+#include
+#include
+#include
+#include "ogg.h"
+
+#define BUFFER_INCREMENT 256
+
+static const unsigned long mask[]=
+{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
+ 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
+ 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
+ 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
+ 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
+ 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
+ 0x3fffffff,0x7fffffff,0xffffffff };
+
+static const unsigned int mask8B[]=
+{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
+
+void oggpack_writeinit(oggpack_buffer *b){
+ memset(b,0,sizeof(*b));
+ b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
+ b->buffer[0]='\0';
+ b->storage=BUFFER_INCREMENT;
+}
+
+void oggpackB_writeinit(oggpack_buffer *b){
+ oggpack_writeinit(b);
+}
+
+int oggpack_writecheck(oggpack_buffer *b){
+ if(!b->ptr || !b->storage)return -1;
+ return 0;
+}
+
+int oggpackB_writecheck(oggpack_buffer *b){
+ return oggpack_writecheck(b);
+}
+
+void oggpack_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask[bits];
+ }
+}
+
+void oggpackB_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask8B[bits];
+ }
+}
+
+/* Takes only up to 32 bits. */
+void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value&=mask[bits];
+ bits+=b->endbit;
+
+ b->ptr[0]|=value<endbit;
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(8-b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(16-b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(24-b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value>>(32-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+/* Takes only up to 32 bits. */
+void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value=(value&mask[bits])<<(32-bits);
+ bits+=b->endbit;
+
+ b->ptr[0]|=value>>(24+b->endbit);
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(16+b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(8+b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value<<(8-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpack_write(b,0,bits);
+}
+
+void oggpackB_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpackB_write(b,0,bits);
+}
+
+static void oggpack_writecopy_helper(oggpack_buffer *b,
+ void *source,
+ long bits,
+ void (*w)(oggpack_buffer *,
+ unsigned long,
+ int),
+ int msb){
+ unsigned char *ptr=(unsigned char *)source;
+
+ long bytes=bits/8;
+ long pbytes=(b->endbit+bits)/8;
+ bits-=bytes*8;
+
+ /* expand storage up-front */
+ if(b->endbyte+pbytes>=b->storage){
+ void *ret;
+ if(!b->ptr) goto err;
+ if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err;
+ b->storage=b->endbyte+pbytes+BUFFER_INCREMENT;
+ ret=_ogg_realloc(b->buffer,b->storage);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ /* copy whole octets */
+ if(b->endbit){
+ int i;
+ /* unaligned copy. Do it the hard way. */
+ for(i=0;iptr,source,bytes);
+ b->ptr+=bytes;
+ b->endbyte+=bytes;
+ *b->ptr=0;
+ }
+
+ /* copy trailing bits */
+ if(bits){
+ if(msb)
+ w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
+ else
+ w(b,(unsigned long)(ptr[bytes]),bits);
+ }
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpack_write,0);
+}
+
+void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpackB_write,1);
+}
+
+void oggpack_reset(oggpack_buffer *b){
+ if(!b->ptr)return;
+ b->ptr=b->buffer;
+ b->buffer[0]=0;
+ b->endbit=b->endbyte=0;
+}
+
+void oggpackB_reset(oggpack_buffer *b){
+ oggpack_reset(b);
+}
+
+void oggpack_writeclear(oggpack_buffer *b){
+ if(b->buffer)_ogg_free(b->buffer);
+ memset(b,0,sizeof(*b));
+}
+
+void oggpackB_writeclear(oggpack_buffer *b){
+ oggpack_writeclear(b);
+}
+
+void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ memset(b,0,sizeof(*b));
+ b->buffer=b->ptr=buf;
+ b->storage=bytes;
+}
+
+void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ oggpack_readinit(b,buf,bytes);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpack_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) return -1;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ return(m&ret);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpackB_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ int m=32-bits;
+
+ if(m<0 || m>32) return -1;
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1);
+}
+
+long oggpack_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>b->endbit)&1);
+}
+
+long oggpackB_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>(7-b->endbit))&1);
+}
+
+void oggpack_adv(oggpack_buffer *b,int bits){
+ bits+=b->endbit;
+
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+}
+
+void oggpackB_adv(oggpack_buffer *b,int bits){
+ oggpack_adv(b,bits);
+}
+
+void oggpack_adv1(oggpack_buffer *b){
+ if(++(b->endbit)>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+}
+
+void oggpackB_adv1(oggpack_buffer *b){
+ oggpack_adv1(b);
+}
+
+/* bits <= 32 */
+long oggpack_read(oggpack_buffer *b,int bits){
+ long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) goto err;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit){
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ }
+ ret&=m;
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return ret;
+
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+/* bits <= 32 */
+long oggpackB_read(oggpack_buffer *b,int bits){
+ long ret;
+ long m=32-bits;
+
+ if(m<0 || m>32) goto err;
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1);
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return ret;
+
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpack_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>b->endbit)&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpackB_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>(7-b->endbit))&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpack_bytes(oggpack_buffer *b){
+ return(b->endbyte+(b->endbit+7)/8);
+}
+
+long oggpack_bits(oggpack_buffer *b){
+ return(b->endbyte*8+b->endbit);
+}
+
+long oggpackB_bytes(oggpack_buffer *b){
+ return oggpack_bytes(b);
+}
+
+long oggpackB_bits(oggpack_buffer *b){
+ return oggpack_bits(b);
+}
+
+unsigned char *oggpack_get_buffer(oggpack_buffer *b){
+ return(b->buffer);
+}
+
+unsigned char *oggpackB_get_buffer(oggpack_buffer *b){
+ return oggpack_get_buffer(b);
+}
+
+/* Self test of the bitwise routines; everything else is based on
+ them, so they damned well better be solid. */
+
+#ifdef _V_SELFTEST
+#include
+
+static int ilog(unsigned int v){
+ int ret=0;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
+oggpack_buffer o;
+oggpack_buffer r;
+
+void report(char *in){
+ fprintf(stderr,"%s",in);
+ exit(1);
+}
+
+void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpack_reset(&o);
+ for(i=0;i
+#include
+#include
+#include "ogg.h"
+
+/* A complete description of Ogg framing exists in docs/framing.html */
+
+int ogg_page_version(const ogg_page *og){
+ return((int)(og->header[4]));
+}
+
+int ogg_page_continued(const ogg_page *og){
+ return((int)(og->header[5]&0x01));
+}
+
+int ogg_page_bos(const ogg_page *og){
+ return((int)(og->header[5]&0x02));
+}
+
+int ogg_page_eos(const ogg_page *og){
+ return((int)(og->header[5]&0x04));
+}
+
+ogg_int64_t ogg_page_granulepos(const ogg_page *og){
+ unsigned char *page=og->header;
+ ogg_int64_t granulepos=page[13]&(0xff);
+ granulepos= (granulepos<<8)|(page[12]&0xff);
+ granulepos= (granulepos<<8)|(page[11]&0xff);
+ granulepos= (granulepos<<8)|(page[10]&0xff);
+ granulepos= (granulepos<<8)|(page[9]&0xff);
+ granulepos= (granulepos<<8)|(page[8]&0xff);
+ granulepos= (granulepos<<8)|(page[7]&0xff);
+ granulepos= (granulepos<<8)|(page[6]&0xff);
+ return(granulepos);
+}
+
+int ogg_page_serialno(const ogg_page *og){
+ return(og->header[14] |
+ (og->header[15]<<8) |
+ (og->header[16]<<16) |
+ (og->header[17]<<24));
+}
+
+long ogg_page_pageno(const ogg_page *og){
+ return(og->header[18] |
+ (og->header[19]<<8) |
+ (og->header[20]<<16) |
+ (og->header[21]<<24));
+}
+
+
+
+/* returns the number of packets that are completed on this page (if
+ the leading packet is begun on a previous page, but ends on this
+ page, it's counted */
+
+/* NOTE:
+ If a page consists of a packet begun on a previous page, and a new
+ packet begun (but not completed) on this page, the return will be:
+ ogg_page_packets(page) ==1,
+ ogg_page_continued(page) !=0
+
+ If a page happens to be a single packet that was begun on a
+ previous page, and spans to the next page (in the case of a three or
+ more page packet), the return will be:
+ ogg_page_packets(page) ==0,
+ ogg_page_continued(page) !=0
+*/
+
+int ogg_page_packets(const ogg_page *og){
+ int i,n=og->header[26],count=0;
+ for(i=0;iheader[27+i]<255)count++;
+ return(count);
+}
+
+
+#if 0
+/* helper to initialize lookup for direct-table CRC (illustrative; we
+ use the static init below) */
+
+static ogg_uint32_t _ogg_crc_entry(unsigned long index){
+ int i;
+ unsigned long r;
+
+ r = index << 24;
+ for (i=0; i<8; i++)
+ if (r & 0x80000000UL)
+ r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ else
+ r<<=1;
+ return (r & 0xffffffffUL);
+}
+#endif
+
+static const ogg_uint32_t crc_lookup[256]={
+ 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
+ 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
+ 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
+ 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
+ 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
+ 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
+ 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
+ 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
+ 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
+ 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
+ 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
+ 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
+ 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
+ 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
+ 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
+ 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
+ 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
+ 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
+ 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
+ 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
+ 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
+ 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
+ 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
+ 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
+ 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
+ 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
+ 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
+ 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
+ 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
+ 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
+ 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
+ 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
+ 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
+ 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
+ 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
+ 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
+ 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
+ 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
+ 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
+ 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
+ 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
+ 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
+ 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
+ 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
+ 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
+ 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
+ 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
+ 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
+ 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
+ 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
+ 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
+ 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
+ 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
+ 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
+ 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
+ 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
+ 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
+ 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
+ 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
+ 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
+ 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
+ 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
+ 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
+ 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
+
+/* init the encode/decode logical stream state */
+
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+ if(os){
+ memset(os,0,sizeof(*os));
+ os->body_storage=16*1024;
+ os->lacing_storage=1024;
+
+ os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
+ os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
+ os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
+
+ if(!os->body_data || !os->lacing_vals || !os->granule_vals){
+ ogg_stream_clear(os);
+ return -1;
+ }
+
+ os->serialno=serialno;
+
+ return(0);
+ }
+ return(-1);
+}
+
+/* async/delayed error detection for the ogg_stream_state */
+int ogg_stream_check(ogg_stream_state *os){
+ if(!os || !os->body_data) return -1;
+ return 0;
+}
+
+/* _clear does not free os, only the non-flat storage within */
+int ogg_stream_clear(ogg_stream_state *os){
+ if(os){
+ if(os->body_data)_ogg_free(os->body_data);
+ if(os->lacing_vals)_ogg_free(os->lacing_vals);
+ if(os->granule_vals)_ogg_free(os->granule_vals);
+
+ memset(os,0,sizeof(*os));
+ }
+ return(0);
+}
+
+int ogg_stream_destroy(ogg_stream_state *os){
+ if(os){
+ ogg_stream_clear(os);
+ _ogg_free(os);
+ }
+ return(0);
+}
+
+/* Helpers for ogg_stream_encode; this keeps the structure and
+ what's happening fairly clear */
+
+static int _os_body_expand(ogg_stream_state *os,long needed){
+ if(os->body_storage-needed<=os->body_fill){
+ long body_storage;
+ void *ret;
+ if(os->body_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ body_storage=os->body_storage+needed;
+ if(body_storagebody_data,body_storage*sizeof(*os->body_data));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->body_storage=body_storage;
+ os->body_data=ret;
+ }
+ return 0;
+}
+
+static int _os_lacing_expand(ogg_stream_state *os,long needed){
+ if(os->lacing_storage-needed<=os->lacing_fill){
+ long lacing_storage;
+ void *ret;
+ if(os->lacing_storage>LONG_MAX-needed){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ lacing_storage=os->lacing_storage+needed;
+ if(lacing_storagelacing_vals,lacing_storage*sizeof(*os->lacing_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->lacing_vals=ret;
+ ret=_ogg_realloc(os->granule_vals,lacing_storage*
+ sizeof(*os->granule_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->granule_vals=ret;
+ os->lacing_storage=lacing_storage;
+ }
+ return 0;
+}
+
+/* checksum the page */
+/* Direct table CRC; note that this will be faster in the future if we
+ perform the checksum simultaneously with other copies */
+
+void ogg_page_checksum_set(ogg_page *og){
+ if(og){
+ ogg_uint32_t crc_reg=0;
+ int i;
+
+ /* safety; needed for API behavior, but not framing code */
+ og->header[22]=0;
+ og->header[23]=0;
+ og->header[24]=0;
+ og->header[25]=0;
+
+ for(i=0;iheader_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
+ for(i=0;ibody_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
+
+ og->header[22]=(unsigned char)(crc_reg&0xff);
+ og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
+ og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
+ og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
+ }
+}
+
+/* submit data to the internal buffer of the framing engine */
+int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
+ long e_o_s, ogg_int64_t granulepos){
+
+ long bytes = 0, lacing_vals;
+ int i;
+
+ if(ogg_stream_check(os)) return -1;
+ if(!iov) return 0;
+
+ for (i = 0; i < count; ++i){
+ if(iov[i].iov_len>LONG_MAX) return -1;
+ if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
+ bytes += (long)iov[i].iov_len;
+ }
+ lacing_vals=bytes/255+1;
+
+ if(os->body_returned){
+ /* advance packet data according to the body_returned pointer. We
+ had to keep it around to return a pointer into the buffer last
+ call */
+
+ os->body_fill-=os->body_returned;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+os->body_returned,
+ os->body_fill);
+ os->body_returned=0;
+ }
+
+ /* make sure we have the buffer storage */
+ if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
+ return -1;
+
+ /* Copy in the submitted packet. Yes, the copy is a waste; this is
+ the liability of overly clean abstraction for the time being. It
+ will actually be fairly easy to eliminate the extra copy in the
+ future */
+
+ for (i = 0; i < count; ++i) {
+ memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
+ os->body_fill += (int)iov[i].iov_len;
+ }
+
+ /* Store lacing vals for this packet */
+ for(i=0;ilacing_vals[os->lacing_fill+i]=255;
+ os->granule_vals[os->lacing_fill+i]=os->granulepos;
+ }
+ os->lacing_vals[os->lacing_fill+i]=bytes%255;
+ os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
+
+ /* flag the first segment as the beginning of the packet */
+ os->lacing_vals[os->lacing_fill]|= 0x100;
+
+ os->lacing_fill+=lacing_vals;
+
+ /* for the sake of completeness */
+ os->packetno++;
+
+ if(e_o_s)os->e_o_s=1;
+
+ return(0);
+}
+
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+ ogg_iovec_t iov;
+ iov.iov_base = op->packet;
+ iov.iov_len = op->bytes;
+ return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
+}
+
+/* Conditionally flush a page; force==0 will only flush nominal-size
+ pages, force==1 forces us to flush a page regardless of page size
+ so long as there's any data available at all. */
+static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
+ int i;
+ int vals=0;
+ int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
+ int bytes=0;
+ long acc=0;
+ ogg_int64_t granule_pos=-1;
+
+ if(ogg_stream_check(os)) return(0);
+ if(maxvals==0) return(0);
+
+ /* construct a page */
+ /* decide how many segments to include */
+
+ /* If this is the initial header case, the first page must only include
+ the initial header packet */
+ if(os->b_o_s==0){ /* 'initial header page' case */
+ granule_pos=0;
+ for(vals=0;valslacing_vals[vals]&0x0ff)<255){
+ vals++;
+ break;
+ }
+ }
+ }else{
+
+ /* The extra packets_done, packet_just_done logic here attempts to do two things:
+ 1) Don't unneccessarily span pages.
+ 2) Unless necessary, don't flush pages if there are less than four packets on
+ them; this expands page size to reduce unneccessary overhead if incoming packets
+ are large.
+ These are not necessary behaviors, just 'always better than naive flushing'
+ without requiring an application to explicitly request a specific optimized
+ behavior. We'll want an explicit behavior setup pathway eventually as well. */
+
+ int packets_done=0;
+ int packet_just_done=0;
+ for(vals=0;valsnfill && packet_just_done>=4){
+ force=1;
+ break;
+ }
+ acc+=os->lacing_vals[vals]&0x0ff;
+ if((os->lacing_vals[vals]&0xff)<255){
+ granule_pos=os->granule_vals[vals];
+ packet_just_done=++packets_done;
+ }else
+ packet_just_done=0;
+ }
+ if(vals==255)force=1;
+ }
+
+ if(!force) return(0);
+
+ /* construct the header in temp storage */
+ memcpy(os->header,"OggS",4);
+
+ /* stream structure version */
+ os->header[4]=0x00;
+
+ /* continued packet flag? */
+ os->header[5]=0x00;
+ if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
+ /* first page flag? */
+ if(os->b_o_s==0)os->header[5]|=0x02;
+ /* last page flag? */
+ if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
+ os->b_o_s=1;
+
+ /* 64 bits of PCM position */
+ for(i=6;i<14;i++){
+ os->header[i]=(unsigned char)(granule_pos&0xff);
+ granule_pos>>=8;
+ }
+
+ /* 32 bits of stream serial number */
+ {
+ long serialno=os->serialno;
+ for(i=14;i<18;i++){
+ os->header[i]=(unsigned char)(serialno&0xff);
+ serialno>>=8;
+ }
+ }
+
+ /* 32 bits of page counter (we have both counter and page header
+ because this val can roll over) */
+ if(os->pageno==-1)os->pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
+ {
+ long pageno=os->pageno++;
+ for(i=18;i<22;i++){
+ os->header[i]=(unsigned char)(pageno&0xff);
+ pageno>>=8;
+ }
+ }
+
+ /* zero for computation; filled in later */
+ os->header[22]=0;
+ os->header[23]=0;
+ os->header[24]=0;
+ os->header[25]=0;
+
+ /* segment table */
+ os->header[26]=(unsigned char)(vals&0xff);
+ for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
+
+ /* set pointers in the ogg_page struct */
+ og->header=os->header;
+ og->header_len=os->header_fill=vals+27;
+ og->body=os->body_data+os->body_returned;
+ og->body_len=bytes;
+
+ /* advance the lacing data and set the body_returned pointer */
+
+ os->lacing_fill-=vals;
+ memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
+ os->body_returned+=bytes;
+
+ /* calculate the checksum */
+
+ ogg_page_checksum_set(og);
+
+ /* done */
+ return(1);
+}
+
+/* This will flush remaining packets into a page (returning nonzero),
+ even if there is not enough data to trigger a flush normally
+ (undersized page). If there are no packets or partial packets to
+ flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
+ try to flush a normal sized page like ogg_stream_pageout; a call to
+ ogg_stream_flush does not guarantee that all packets have flushed.
+ Only a return value of 0 from ogg_stream_flush indicates all packet
+ data is flushed into pages.
+
+ since ogg_stream_flush will flush the last page in a stream even if
+ it's undersized, you almost certainly want to use ogg_stream_pageout
+ (and *not* ogg_stream_flush) unless you specifically need to flush
+ a page regardless of size in the middle of a stream. */
+
+int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
+ return ogg_stream_flush_i(os,og,1,4096);
+}
+
+/* Like the above, but an argument is provided to adjust the nominal
+ page size for applications which are smart enough to provide their
+ own delay based flushing */
+
+int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
+ return ogg_stream_flush_i(os,og,1,nfill);
+}
+
+/* This constructs pages from buffered packet segments. The pointers
+returned are to static buffers; do not free. The returned buffers are
+good only until the next call (using the same ogg_stream_state) */
+
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,4096));
+}
+
+/* Like the above, but an argument is provided to adjust the nominal
+page size for applications which are smart enough to provide their
+own delay based flushing */
+
+int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,nfill));
+}
+
+int ogg_stream_eos(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return 1;
+ return os->e_o_s;
+}
+
+/* DECODING PRIMITIVES: packet streaming layer **********************/
+
+/* This has two layers to place more of the multi-serialno and paging
+ control in the application's hands. First, we expose a data buffer
+ using ogg_sync_buffer(). The app either copies into the
+ buffer, or passes it directly to read(), etc. We then call
+ ogg_sync_wrote() to tell how many bytes we just added.
+
+ Pages are returned (pointers into the buffer in ogg_sync_state)
+ by ogg_sync_pageout(). The page is then submitted to
+ ogg_stream_pagein() along with the appropriate
+ ogg_stream_state* (ie, matching serialno). We then get raw
+ packets out calling ogg_stream_packetout() with a
+ ogg_stream_state. */
+
+/* initialize the struct to a known state */
+int ogg_sync_init(ogg_sync_state *oy){
+ if(oy){
+ oy->storage = -1; /* used as a readiness flag */
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+/* clear non-flat storage within */
+int ogg_sync_clear(ogg_sync_state *oy){
+ if(oy){
+ if(oy->data)_ogg_free(oy->data);
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+int ogg_sync_destroy(ogg_sync_state *oy){
+ if(oy){
+ ogg_sync_clear(oy);
+ _ogg_free(oy);
+ }
+ return(0);
+}
+
+int ogg_sync_check(ogg_sync_state *oy){
+ if(oy->storage<0) return -1;
+ return 0;
+}
+
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
+ if(ogg_sync_check(oy)) return NULL;
+
+ /* first, clear out any space that has been previously returned */
+ if(oy->returned){
+ oy->fill-=oy->returned;
+ if(oy->fill>0)
+ memmove(oy->data,oy->data+oy->returned,oy->fill);
+ oy->returned=0;
+ }
+
+ if(size>oy->storage-oy->fill){
+ /* We need to extend the internal buffer */
+ long newsize=size+oy->fill+4096; /* an extra page to be nice */
+ void *ret;
+
+ if(oy->data)
+ ret=_ogg_realloc(oy->data,newsize);
+ else
+ ret=_ogg_malloc(newsize);
+ if(!ret){
+ ogg_sync_clear(oy);
+ return NULL;
+ }
+ oy->data=ret;
+ oy->storage=newsize;
+ }
+
+ /* expose a segment at least as large as requested at the fill mark */
+ return((char *)oy->data+oy->fill);
+}
+
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+ if(ogg_sync_check(oy))return -1;
+ if(oy->fill+bytes>oy->storage)return -1;
+ oy->fill+=bytes;
+ return(0);
+}
+
+/* sync the stream. This is meant to be useful for finding page
+ boundaries.
+
+ return values for this:
+ -n) skipped n bytes
+ 0) page not ready; more data (no bytes skipped)
+ n) page synced at current location; page length n bytes
+
+*/
+
+long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
+ unsigned char *page=oy->data+oy->returned;
+ unsigned char *next;
+ long bytes=oy->fill-oy->returned;
+
+ if(ogg_sync_check(oy))return 0;
+
+ if(oy->headerbytes==0){
+ int headerbytes,i;
+ if(bytes<27)return(0); /* not enough for a header */
+
+ /* verify capture pattern */
+ if(memcmp(page,"OggS",4))goto sync_fail;
+
+ headerbytes=page[26]+27;
+ if(bytesbodybytes+=page[27+i];
+ oy->headerbytes=headerbytes;
+ }
+
+ if(oy->bodybytes+oy->headerbytes>bytes)return(0);
+
+ /* The whole test page is buffered. Verify the checksum */
+ {
+ /* Grab the checksum bytes, set the header field to zero */
+ char chksum[4];
+ ogg_page log;
+
+ memcpy(chksum,page+22,4);
+ memset(page+22,0,4);
+
+ /* set up a temp page struct and recompute the checksum */
+ log.header=page;
+ log.header_len=oy->headerbytes;
+ log.body=page+oy->headerbytes;
+ log.body_len=oy->bodybytes;
+ ogg_page_checksum_set(&log);
+
+ /* Compare */
+ if(memcmp(chksum,page+22,4)){
+ /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
+ at all) */
+ /* replace the computed checksum with the one actually read in */
+ memcpy(page+22,chksum,4);
+
+ /* Bad checksum. Lose sync */
+ goto sync_fail;
+ }
+ }
+
+ /* yes, have a whole page all ready to go */
+ {
+ unsigned char *page=oy->data+oy->returned;
+ long bytes;
+
+ if(og){
+ og->header=page;
+ og->header_len=oy->headerbytes;
+ og->body=page+oy->headerbytes;
+ og->body_len=oy->bodybytes;
+ }
+
+ oy->unsynced=0;
+ oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(bytes);
+ }
+
+ sync_fail:
+
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+
+ /* search for possible capture */
+ next=memchr(page+1,'O',bytes-1);
+ if(!next)
+ next=oy->data+oy->fill;
+
+ oy->returned=(int)(next-oy->data);
+ return((long)-(next-page));
+}
+
+/* sync the stream and get a page. Keep trying until we find a page.
+ Suppress 'sync errors' after reporting the first.
+
+ return values:
+ -1) recapture (hole in data)
+ 0) need more data
+ 1) page returned
+
+ Returns pointers into buffered data; invalidated by next call to
+ _stream, _clear, _init, or _buffer */
+
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
+
+ if(ogg_sync_check(oy))return 0;
+
+ /* all we need to do is verify a page at the head of the stream
+ buffer. If it doesn't verify, we look for the next potential
+ frame */
+
+ for(;;){
+ long ret=ogg_sync_pageseek(oy,og);
+ if(ret>0){
+ /* have a page */
+ return(1);
+ }
+ if(ret==0){
+ /* need more data */
+ return(0);
+ }
+
+ /* head did not start a synced page... skipped some bytes */
+ if(!oy->unsynced){
+ oy->unsynced=1;
+ return(-1);
+ }
+
+ /* loop. keep looking */
+
+ }
+}
+
+/* add the incoming page to the stream state; we decompose the page
+ into packet segments here as well. */
+
+int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
+ unsigned char *header=og->header;
+ unsigned char *body=og->body;
+ long bodysize=og->body_len;
+ int segptr=0;
+
+ int version=ogg_page_version(og);
+ int continued=ogg_page_continued(og);
+ int bos=ogg_page_bos(og);
+ int eos=ogg_page_eos(og);
+ ogg_int64_t granulepos=ogg_page_granulepos(og);
+ int serialno=ogg_page_serialno(og);
+ long pageno=ogg_page_pageno(og);
+ int segments=header[26];
+
+ if(ogg_stream_check(os)) return -1;
+
+ /* clean up 'returned data' */
+ {
+ long lr=os->lacing_returned;
+ long br=os->body_returned;
+
+ /* body data */
+ if(br){
+ os->body_fill-=br;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+br,os->body_fill);
+ os->body_returned=0;
+ }
+
+ if(lr){
+ /* segment table */
+ if(os->lacing_fill-lr){
+ memmove(os->lacing_vals,os->lacing_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->granule_vals));
+ }
+ os->lacing_fill-=lr;
+ os->lacing_packet-=lr;
+ os->lacing_returned=0;
+ }
+ }
+
+ /* check the serial number */
+ if(serialno!=os->serialno)return(-1);
+ if(version>0)return(-1);
+
+ if(_os_lacing_expand(os,segments+1)) return -1;
+
+ /* are we in sequence? */
+ if(pageno!=os->pageno){
+ int i;
+
+ /* unroll previous partial packet (if any) */
+ for(i=os->lacing_packet;ilacing_fill;i++)
+ os->body_fill-=os->lacing_vals[i]&0xff;
+ os->lacing_fill=os->lacing_packet;
+
+ /* make a note of dropped data in segment table */
+ if(os->pageno!=-1){
+ os->lacing_vals[os->lacing_fill++]=0x400;
+ os->lacing_packet++;
+ }
+ }
+
+ /* are we a 'continued packet' page? If so, we may need to skip
+ some segments */
+ if(continued){
+ if(os->lacing_fill<1 ||
+ (os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
+ os->lacing_vals[os->lacing_fill-1]==0x400){
+ bos=0;
+ for(;segptrbody_data+os->body_fill,body,bodysize);
+ os->body_fill+=bodysize;
+ }
+
+ {
+ int saved=-1;
+ while(segptrlacing_vals[os->lacing_fill]=val;
+ os->granule_vals[os->lacing_fill]=-1;
+
+ if(bos){
+ os->lacing_vals[os->lacing_fill]|=0x100;
+ bos=0;
+ }
+
+ if(val<255)saved=os->lacing_fill;
+
+ os->lacing_fill++;
+ segptr++;
+
+ if(val<255)os->lacing_packet=os->lacing_fill;
+ }
+
+ /* set the granulepos on the last granuleval of the last full packet */
+ if(saved!=-1){
+ os->granule_vals[saved]=granulepos;
+ }
+
+ }
+
+ if(eos){
+ os->e_o_s=1;
+ if(os->lacing_fill>0)
+ os->lacing_vals[os->lacing_fill-1]|=0x200;
+ }
+
+ os->pageno=pageno+1;
+
+ return(0);
+}
+
+/* clear things to an initial state. Good to call, eg, before seeking */
+int ogg_sync_reset(ogg_sync_state *oy){
+ if(ogg_sync_check(oy))return -1;
+
+ oy->fill=0;
+ oy->returned=0;
+ oy->unsynced=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(0);
+}
+
+int ogg_stream_reset(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return -1;
+
+ os->body_fill=0;
+ os->body_returned=0;
+
+ os->lacing_fill=0;
+ os->lacing_packet=0;
+ os->lacing_returned=0;
+
+ os->header_fill=0;
+
+ os->e_o_s=0;
+ os->b_o_s=0;
+ os->pageno=-1;
+ os->packetno=0;
+ os->granulepos=0;
+
+ return(0);
+}
+
+int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
+ if(ogg_stream_check(os)) return -1;
+ ogg_stream_reset(os);
+ os->serialno=serialno;
+ return(0);
+}
+
+static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
+
+ /* The last part of decode. We have the stream broken into packet
+ segments. Now we need to group them into packets (or return the
+ out of sync markers) */
+
+ int ptr=os->lacing_returned;
+
+ if(os->lacing_packet<=ptr)return(0);
+
+ if(os->lacing_vals[ptr]&0x400){
+ /* we need to tell the codec there's a gap; it might need to
+ handle previous packet dependencies. */
+ os->lacing_returned++;
+ os->packetno++;
+ return(-1);
+ }
+
+ if(!op && !adv)return(1); /* just using peek as an inexpensive way
+ to ask if there's a whole packet
+ waiting */
+
+ /* Gather the whole packet. We'll have no holes or a partial packet */
+ {
+ int size=os->lacing_vals[ptr]&0xff;
+ long bytes=size;
+ int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+
+ while(size==255){
+ int val=os->lacing_vals[++ptr];
+ size=val&0xff;
+ if(val&0x200)eos=0x200;
+ bytes+=size;
+ }
+
+ if(op){
+ op->e_o_s=eos;
+ op->b_o_s=bos;
+ op->packet=os->body_data+os->body_returned;
+ op->packetno=os->packetno;
+ op->granulepos=os->granule_vals[ptr];
+ op->bytes=bytes;
+ }
+
+ if(adv){
+ os->body_returned+=bytes;
+ os->lacing_returned=ptr+1;
+ os->packetno++;
+ }
+ }
+ return(1);
+}
+
+int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
+ return _packetout(os,op,1);
+}
+
+int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
+ return _packetout(os,op,0);
+}
+
+void ogg_packet_clear(ogg_packet *op) {
+ _ogg_free(op->packet);
+ memset(op, 0, sizeof(*op));
+}
+
+#ifdef _V_SELFTEST
+#include
+
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+void checkpacket(ogg_packet *op,long len, int no, long pos){
+ long j;
+ static int sequence=0;
+ static int lastno=0;
+
+ if(op->bytes!=len){
+ fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
+ exit(1);
+ }
+ if(op->granulepos!=pos){
+ fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
+ exit(1);
+ }
+
+ /* packet number just follows sequence/gap; adjust the input number
+ for that */
+ if(no==0){
+ sequence=0;
+ }else{
+ sequence++;
+ if(no>lastno+1)
+ sequence++;
+ }
+ lastno=no;
+ if(op->packetno!=sequence){
+ fprintf(stderr,"incorrect packet sequence %ld != %d\n",
+ (long)(op->packetno),sequence);
+ exit(1);
+ }
+
+ /* Test data */
+ for(j=0;jbytes;j++)
+ if(op->packet[j]!=((j+no)&0xff)){
+ fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
+ j,op->packet[j],(j+no)&0xff);
+ exit(1);
+ }
+}
+
+void check_page(unsigned char *data,const int *header,ogg_page *og){
+ long j;
+ /* Test data */
+ for(j=0;jbody_len;j++)
+ if(og->body[j]!=data[j]){
+ fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
+ j,data[j],og->body[j]);
+ exit(1);
+ }
+
+ /* Test header */
+ for(j=0;jheader_len;j++){
+ if(og->header[j]!=header[j]){
+ fprintf(stderr,"header content mismatch at pos %ld:\n",j);
+ for(j=0;jheader[j]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
+ }
+ if(og->header_len!=header[26]+27){
+ fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
+ og->header_len,header[26]+27);
+ exit(1);
+ }
+}
+
+void print_header(ogg_page *og){
+ int j;
+ fprintf(stderr,"\nHEADER:\n");
+ fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
+ og->header[0],og->header[1],og->header[2],og->header[3],
+ (int)og->header[4],(int)og->header[5]);
+
+ fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
+ (og->header[9]<<24)|(og->header[8]<<16)|
+ (og->header[7]<<8)|og->header[6],
+ (og->header[17]<<24)|(og->header[16]<<16)|
+ (og->header[15]<<8)|og->header[14],
+ ((long)(og->header[21])<<24)|(og->header[20]<<16)|
+ (og->header[19]<<8)|og->header[18]);
+
+ fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
+ (int)og->header[22],(int)og->header[23],
+ (int)og->header[24],(int)og->header[25],
+ (int)og->header[26]);
+
+ for(j=27;jheader_len;j++)
+ fprintf(stderr,"%d ",(int)og->header[j]);
+ fprintf(stderr,")\n\n");
+}
+
+void copy_page(ogg_page *og){
+ unsigned char *temp=_ogg_malloc(og->header_len);
+ memcpy(temp,og->header,og->header_len);
+ og->header=temp;
+
+ temp=_ogg_malloc(og->body_len);
+ memcpy(temp,og->body,og->body_len);
+ og->body=temp;
+}
+
+void free_page(ogg_page *og){
+ _ogg_free (og->header);
+ _ogg_free (og->body);
+}
+
+void error(void){
+ fprintf(stderr,"error!\n");
+ exit(1);
+}
+
+/* 17 only */
+const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+
+/* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+
+/* nil packets; beginning,middle,end */
+const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+
+/* large initial packet */
+const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+
+
+/* continuing packet test */
+const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xf8,0x3c,0x19,0x79,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x38,0xe6,0xb6,0x28,
+ 6,
+ 255,220,255,4,255,0};
+
+
+/* spill expansion test */
+const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xce,0x8f,0x17,0x1a,
+ 23,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
+
+
+const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x9b,0xb2,0x50,0xa1,
+ 1,
+ 0};
+
+/* page with the 255 segment limit */
+const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+
+
+/* packet that overspans over an entire page */
+const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xf4,0x87,0xba,0xf3,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xf7,0x2f,0x6c,0x60,
+ 5,
+ 254,255,4,255,0};
+
+/* packet that overspans over an entire page */
+const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,
+ 0};
+
+int compare_packet(const ogg_packet *op1, const ogg_packet *op2){
+ if(op1->packet!=op2->packet){
+ fprintf(stderr,"op1->packet != op2->packet\n");
+ return(1);
+ }
+ if(op1->bytes!=op2->bytes){
+ fprintf(stderr,"op1->bytes != op2->bytes\n");
+ return(1);
+ }
+ if(op1->b_o_s!=op2->b_o_s){
+ fprintf(stderr,"op1->b_o_s != op2->b_o_s\n");
+ return(1);
+ }
+ if(op1->e_o_s!=op2->e_o_s){
+ fprintf(stderr,"op1->e_o_s != op2->e_o_s\n");
+ return(1);
+ }
+ if(op1->granulepos!=op2->granulepos){
+ fprintf(stderr,"op1->granulepos != op2->granulepos\n");
+ return(1);
+ }
+ if(op1->packetno!=op2->packetno){
+ fprintf(stderr,"op1->packetno != op2->packetno\n");
+ return(1);
+ }
+ return(0);
+}
+
+void test_pack(const int *pl, const int **headers, int byteskip,
+ int pageskip, int packetskip){
+ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
+ long inptr=0;
+ long outptr=0;
+ long deptr=0;
+ long depacket=0;
+ long granule_pos=7,pageno=0;
+ int i,j,packets,pageout=pageskip;
+ int eosflag=0;
+ int bosflag=0;
+
+ int byteskipcount=0;
+
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
+ ogg_sync_reset(&oy);
+
+ for(packets=0;packetsbyteskip){
+ memcpy(next,og.header,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ byteskipcount+=og.body_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.body,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ ogg_sync_wrote(&oy,next-buf);
+
+ while(1){
+ int ret=ogg_sync_pageout(&oy,&og_de);
+ if(ret==0)break;
+ if(ret<0)continue;
+ /* got a page. Happy happy. Verify that it's good. */
+
+ fprintf(stderr,"(%d), ",pageout);
+
+ check_page(data+deptr,headers[pageout],&og_de);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ /* submit it to deconstitution */
+ ogg_stream_pagein(&os_de,&og_de);
+
+ /* packets out? */
+ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
+ ogg_stream_packetpeek(&os_de,NULL);
+ ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
+
+ /* verify peek and out match */
+ if(compare_packet(&op_de,&op_de2)){
+ fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+
+ /* verify the packet! */
+ /* check data */
+ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
+ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+ /* check bos flag */
+ if(bosflag==0 && op_de.b_o_s==0){
+ fprintf(stderr,"b_o_s flag not set on packet!\n");
+ exit(1);
+ }
+ if(bosflag && op_de.b_o_s){
+ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
+ exit(1);
+ }
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ /* check eos flag */
+ if(eosflag){
+ fprintf(stderr,"Multiple decoded packets with eos flag!\n");
+ exit(1);
+ }
+
+ if(op_de.e_o_s)eosflag=1;
+
+ /* check granulepos flag */
+ if(op_de.granulepos!=-1){
+ fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ _ogg_free(data);
+ if(headers[pageno]!=NULL){
+ fprintf(stderr,"did not write last page!\n");
+ exit(1);
+ }
+ if(headers[pageout]!=NULL){
+ fprintf(stderr,"did not decode last page!\n");
+ exit(1);
+ }
+ if(inptr!=outptr){
+ fprintf(stderr,"encoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=deptr){
+ fprintf(stderr,"decoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=depacket){
+ fprintf(stderr,"decoded packet data incomplete!\n");
+ exit(1);
+ }
+ if(!eosflag){
+ fprintf(stderr,"Never got a packet with EOS set!\n");
+ exit(1);
+ }
+ fprintf(stderr,"ok.\n");
+}
+
+int main(void){
+
+ ogg_stream_init(&os_en,0x04030201);
+ ogg_stream_init(&os_de,0x04030201);
+ ogg_sync_init(&oy);
+
+ /* Exercise each code path in the framing code. Also verify that
+ the checksums are working. */
+
+ {
+ /* 17 only */
+ const int packets[]={17, -1};
+ const int *headret[]={head1_0,NULL};
+
+ fprintf(stderr,"testing single page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
+ const int *headret[]={head1_1,head2_1,NULL};
+
+ fprintf(stderr,"testing basic page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* nil packets; beginning,middle,end */
+ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+ const int *headret[]={head1_2,head2_2,NULL};
+
+ fprintf(stderr,"testing basic nil packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* large initial packet */
+ const int packets[]={4345,259,255,-1};
+ const int *headret[]={head1_3,head2_3,NULL};
+
+ fprintf(stderr,"testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* continuing packet test; with page spill expansion, we have to
+ overflow the lacing table. */
+ const int packets[]={0,65500,259,255,-1};
+ const int *headret[]={head1_4,head2_4,head3_4,NULL};
+
+ fprintf(stderr,"testing single packet page span... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* spill expand packet test */
+ const int packets[]={0,4345,259,255,0,0,-1};
+ const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
+
+ fprintf(stderr,"testing page spill expansion... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ /* page with the 255 segment limit */
+ {
+
+ const int packets[]={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+ const int *headret[]={head1_5,head2_5,head3_5,NULL};
+
+ fprintf(stderr,"testing max packet segments... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* packet that overspans over an entire page */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing very large packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* test for the libogg 1.1.1 resync in large continuation bug
+ found by Josh Coalson) */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing continuation resync in very large packets... ");
+ test_pack(packets,headret,100,2,3);
+ }
+
+ {
+ /* term only page. why not? */
+ const int packets[]={0,100,64770,-1};
+ const int *headret[]={head1_7,head2_7,head3_7,NULL};
+
+ fprintf(stderr,"testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+
+
+ {
+ /* build a bunch of pages for testing */
+ unsigned char *data=_ogg_malloc(1024*1024);
+ int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
+ int inptr=0,i,j;
+ ogg_page og[5];
+
+ ogg_stream_reset(&os_en);
+
+ for(i=0;pl[i]!=-1;i++){
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(j=0;j0)error();
+
+ /* Test fractional page inputs: incomplete fixed header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
+ 5);
+ ogg_sync_wrote(&oy,5);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete body */
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
+ og[1].header_len-28);
+ ogg_sync_wrote(&oy,og[1].header_len-28);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
+ ogg_sync_wrote(&oy,1000);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
+ og[1].body_len-1000);
+ ogg_sync_wrote(&oy,og[1].body_len-1000);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test fractional page inputs: page + incomplete capture */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing sync on 1+partial inputs... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+ og[1].header_len-20);
+ ogg_sync_wrote(&oy,og[1].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing search for capture... ");
+ ogg_sync_reset(&oy);
+
+ /* 'garbage' */
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
+ og[2].header_len-20);
+ ogg_sync_wrote(&oy,og[2].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len);
+ ogg_sync_wrote(&oy,og[2].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: page + garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing recapture... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len-5);
+ ogg_sync_wrote(&oy,og[2].body_len-5);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
+ og[3].header_len);
+ ogg_sync_wrote(&oy,og[3].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
+ og[3].body_len);
+ ogg_sync_wrote(&oy,og[3].body_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Free page data that was previously copied */
+ {
+ for(i=0;i<5;i++){
+ free_page(&og[i]);
+ }
+ }
+ }
+
+ return(0);
+}
+
+#endif
diff -Nru ultracopier-1.6.1.3/libogg/ogg.h ultracopier-2.2.4.4/libogg/ogg.h
--- ultracopier-1.6.1.3/libogg/ogg.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libogg/ogg.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,210 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel libogg include
+ last mod: $Id$
+
+ ********************************************************************/
+#ifndef _OGG_H
+#define _OGG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include "os_types.h"
+
+typedef struct {
+ void *iov_base;
+ size_t iov_len;
+} ogg_iovec_t;
+
+typedef struct {
+ long endbyte;
+ int endbit;
+
+ unsigned char *buffer;
+ unsigned char *ptr;
+ long storage;
+} oggpack_buffer;
+
+/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
+
+typedef struct {
+ unsigned char *header;
+ long header_len;
+ unsigned char *body;
+ long body_len;
+} ogg_page;
+
+/* ogg_stream_state contains the current encode/decode state of a logical
+ Ogg bitstream **********************************************************/
+
+typedef struct {
+ unsigned char *body_data; /* bytes from packet bodies */
+ long body_storage; /* storage elements allocated */
+ long body_fill; /* elements stored; fill mark */
+ long body_returned; /* elements of fill returned */
+
+
+ int *lacing_vals; /* The values that will go to the segment table */
+ ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ long lacing_storage;
+ long lacing_fill;
+ long lacing_packet;
+ long lacing_returned;
+
+ unsigned char header[282]; /* working space for header encode */
+ int header_fill;
+
+ int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int b_o_s; /* set after we've written the initial page
+ of a logical bitstream */
+ long serialno;
+ long pageno;
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
+ ogg_int64_t granulepos;
+
+} ogg_stream_state;
+
+/* ogg_packet is used to encapsulate the data and metadata belonging
+ to a single raw Ogg/Vorbis packet *************************************/
+
+typedef struct {
+ unsigned char *packet;
+ long bytes;
+ long b_o_s;
+ long e_o_s;
+
+ ogg_int64_t granulepos;
+
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
+} ogg_packet;
+
+typedef struct {
+ unsigned char *data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+} ogg_sync_state;
+
+/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+
+extern void oggpack_writeinit(oggpack_buffer *b);
+extern int oggpack_writecheck(oggpack_buffer *b);
+extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpack_writealign(oggpack_buffer *b);
+extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpack_reset(oggpack_buffer *b);
+extern void oggpack_writeclear(oggpack_buffer *b);
+extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpack_look(oggpack_buffer *b,int bits);
+extern long oggpack_look1(oggpack_buffer *b);
+extern void oggpack_adv(oggpack_buffer *b,int bits);
+extern void oggpack_adv1(oggpack_buffer *b);
+extern long oggpack_read(oggpack_buffer *b,int bits);
+extern long oggpack_read1(oggpack_buffer *b);
+extern long oggpack_bytes(oggpack_buffer *b);
+extern long oggpack_bits(oggpack_buffer *b);
+extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
+
+extern void oggpackB_writeinit(oggpack_buffer *b);
+extern int oggpackB_writecheck(oggpack_buffer *b);
+extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpackB_writealign(oggpack_buffer *b);
+extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpackB_reset(oggpack_buffer *b);
+extern void oggpackB_writeclear(oggpack_buffer *b);
+extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpackB_look(oggpack_buffer *b,int bits);
+extern long oggpackB_look1(oggpack_buffer *b);
+extern void oggpackB_adv(oggpack_buffer *b,int bits);
+extern void oggpackB_adv1(oggpack_buffer *b);
+extern long oggpackB_read(oggpack_buffer *b,int bits);
+extern long oggpackB_read1(oggpack_buffer *b);
+extern long oggpackB_bytes(oggpack_buffer *b);
+extern long oggpackB_bits(oggpack_buffer *b);
+extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
+
+/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
+
+extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
+ int count, long e_o_s, ogg_int64_t granulepos);
+extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+
+/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
+
+extern int ogg_sync_init(ogg_sync_state *oy);
+extern int ogg_sync_clear(ogg_sync_state *oy);
+extern int ogg_sync_reset(ogg_sync_state *oy);
+extern int ogg_sync_destroy(ogg_sync_state *oy);
+extern int ogg_sync_check(ogg_sync_state *oy);
+
+extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
+extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
+
+/* Ogg BITSTREAM PRIMITIVES: general ***************************/
+
+extern int ogg_stream_init(ogg_stream_state *os,int serialno);
+extern int ogg_stream_clear(ogg_stream_state *os);
+extern int ogg_stream_reset(ogg_stream_state *os);
+extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int ogg_stream_destroy(ogg_stream_state *os);
+extern int ogg_stream_check(ogg_stream_state *os);
+extern int ogg_stream_eos(ogg_stream_state *os);
+
+extern void ogg_page_checksum_set(ogg_page *og);
+
+extern int ogg_page_version(const ogg_page *og);
+extern int ogg_page_continued(const ogg_page *og);
+extern int ogg_page_bos(const ogg_page *og);
+extern int ogg_page_eos(const ogg_page *og);
+extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
+extern int ogg_page_serialno(const ogg_page *og);
+extern long ogg_page_pageno(const ogg_page *og);
+extern int ogg_page_packets(const ogg_page *og);
+
+extern void ogg_packet_clear(ogg_packet *op);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OGG_H */
diff -Nru ultracopier-1.6.1.3/libogg/os_types.h ultracopier-2.2.4.4/libogg/os_types.h
--- ultracopier-1.6.1.3/libogg/os_types.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/libogg/os_types.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,153 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id$
+
+ ********************************************************************/
+#ifndef _OS_TYPES_H
+#define _OS_TYPES_H
+
+/* make it easy on the folks that want to compile the libs with a
+ different malloc than stdlib */
+#define _ogg_malloc malloc
+#define _ogg_calloc calloc
+#define _ogg_realloc realloc
+#define _ogg_free free
+
+#if defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+ typedef uint64_t ogg_uint64_t;
+# elif defined(__MINGW32__)
+# include
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+ typedef unsigned long long ogg_uint64_t;
+# elif defined(__MWERKS__)
+ typedef long long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+# else
+# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */
+# include
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+ typedef uint64_t ogg_uint64_t;
+# else
+ /* MSVC/Borland */
+ typedef __int64 ogg_int64_t;
+ typedef __int32 ogg_int32_t;
+ typedef unsigned __int32 ogg_uint32_t;
+ typedef __int16 ogg_int16_t;
+ typedef unsigned __int16 ogg_uint16_t;
+# endif
+# endif
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined(__HAIKU__)
+
+ /* Haiku */
+# include
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short ogg_int16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned ogg_uint32_t;
+ typedef short ogg_int16_t;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef signed int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long int ogg_int64_t;
+
+#elif defined(__TMS320C6X__)
+
+ /* TI C64x compiler */
+ typedef signed short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef signed int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long int ogg_int64_t;
+
+#else
+#include
+ typedef int16_t ogg_int16_t;
+ typedef uint16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef uint32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+ typedef uint64_t ogg_uint64_t;
+
+#endif
+
+#endif /* _OS_TYPES_H */
diff -Nru ultracopier-1.6.1.3/little/main-little.cpp ultracopier-2.2.4.4/little/main-little.cpp
--- ultracopier-1.6.1.3/little/main-little.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/little/main-little.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -5,11 +5,15 @@
#include
#include
-#include "../Variable.h"
-#include "../plugins/CopyEngine/Ultracopier/CopyEngineFactory.h"
-#include "../plugins/Themes/Oxygen/ThemesFactory.h"
+#ifndef ULTRACOPIER_LITTLE_RANDOM
+#include "../plugins/CopyEngine/Ultracopier-Spec/CopyEngineFactory.h"
+#else
+#include "../plugins/CopyEngine/Random/CopyEngineFactory.h"
+#endif
+#include "../plugins/Themes/Oxygen2/ThemesFactory.h"
#include "OptionsEngineLittle.h"
#include "../FacilityEngine.h"
+#include "../Version.h"
#include
Themes * interface=NULL;
@@ -41,6 +45,8 @@
void connectInterfaceAndSync();
void periodicSynchronization();
+bool havePause=false;
+
/// \brief Define the main() for the point entry
int main(int argc, char *argv[])
{
@@ -49,6 +55,7 @@
qRegisterMetaType("Ultracopier::CopyMode");
qRegisterMetaType("Ultracopier::ItemOfCopyList");
qRegisterMetaType("std::string");
+ qRegisterMetaType("std::wstring");
qRegisterMetaType >("std::vector");
qRegisterMetaType("Ultracopier::DebugLevel");
qRegisterMetaType("Ultracopier::EngineActionInProgress");
@@ -64,6 +71,7 @@
interface=static_cast(themesFactory.getInstance());
engine=static_cast(copyEngineFactory.getInstance());
+ havePause=copyEngineFactory.havePause();
connectEngine();
connectInterfaceAndSync();
@@ -119,12 +127,12 @@
failed|=!QObject::connect(interface,&Themes::resume, engine,&CopyEngine::resetSpeedDetectedInterface);
failed|=!QObject::connect(interface,&Themes::urlDropped, engine,&CopyEngine::urlDropped,Qt::QueuedConnection);*/
failed|=!QObject::connect(interface,&Themes::cancel, engine,&CopyEngine::cancel,Qt::QueuedConnection);
- failed|=!QObject::connect(engine,&CopyEngine::newActionOnList, engine,&CopyEngine::newActionOnList, Qt::QueuedConnection);
+ failed|=!QObject::connect(engine,&CopyEngine::newActionOnList, interface,&Themes::getActionOnList, Qt::QueuedConnection);
failed|=!QObject::connect(engine,&CopyEngine::pushFileProgression, interface,&Themes::setFileProgression, Qt::QueuedConnection);
failed|=!QObject::connect(engine,&CopyEngine::pushGeneralProgression, interface,&Themes::setGeneralProgression, Qt::QueuedConnection);
- failed|=!QObject::connect(engine,&CopyEngine::pushGeneralProgression, engine,&CopyEngine::pushGeneralProgression, Qt::QueuedConnection);
failed|=!QObject::connect(engine,&CopyEngine::errorToRetry, interface,&Themes::errorToRetry, Qt::QueuedConnection);
+ failed|=!QObject::connect(engine,&CopyEngine::doneTime, interface,&Themes::doneTime, Qt::QueuedConnection);
if(failed)
{
@@ -133,6 +141,7 @@
}
interface->setSupportSpeedLimitation(engine->supportSpeedLimitation());
interface->setCopyType(Ultracopier::CopyType::FileAndFolder);
+ interface->havePause(havePause);
interface->setTransferListOperation(Ultracopier::TransferListOperation::TransferListOperation_None);
interface->actionInProgess(Ultracopier::EngineActionInProgress::Idle);
//interface->isInPause(currentCopyInstance.isPaused);
diff -Nru ultracopier-1.6.1.3/LocalListener.cpp ultracopier-2.2.4.4/LocalListener.cpp
--- ultracopier-1.6.1.3/LocalListener.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/LocalListener.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -83,6 +83,7 @@
int byteWriten =
#endif
localSocket.write(blockToSend);
+ localSocket.readAll();
#ifdef ULTRACOPIER_DEBUG
if(!localSocket.isValid())
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"localSocket is not valid!");
@@ -92,7 +93,7 @@
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"blockToSend("+std::to_string(blockToSend.size())+
")!=byteWriten("+std::to_string(byteWriten)+")");
#endif // ULTRACOPIER_DEBUG
- if(localSocket.waitForBytesWritten(200))
+ if(localSocket.waitForBytesWritten())
{
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"Block send correctly");
}
@@ -107,7 +108,12 @@
}
while(block.size());
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"disconnect the socket");
+ localSocket.readAll();
+ localSocket.waitForBytesWritten();
+ QThread::msleep(50);
localSocket.disconnectFromServer();
+ QThread::msleep(50);
+ localSocket.waitForDisconnected();
return true;
}
else
diff -Nru ultracopier-1.6.1.3/main.cpp ultracopier-2.2.4.4/main.cpp
--- ultracopier-1.6.1.3/main.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/main.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -54,10 +54,12 @@
KeysList.push_back(std::pair("key",""));
KeysList.push_back(std::pair("ActionOnManualOpen","1"));
KeysList.push_back(std::pair("GroupWindowWhen","0"));
- KeysList.push_back(std::pair("displayOSSpecific","true"));
+ KeysList.push_back(std::pair("displayOSSpecific2","true"));
KeysList.push_back(std::pair("confirmToGroupWindows","true"));
- KeysList.push_back(std::pair("remainingTimeAlgorithm","1"));
+ KeysList.push_back(std::pair("remainingTimeAlgorithm","0"));
KeysList.push_back(std::pair("portable","false"));
+ KeysList.push_back(std::pair("soundFile","finish.opus"));
+ KeysList.push_back(std::pair("soundWhenFinish","false"));
#ifdef ULTRACOPIER_INTERNET_SUPPORT
#if defined(Q_OS_WIN32) || defined(Q_OS_MAC)
KeysList.push_back(std::pair("checkTheUpdate","true"));
@@ -68,7 +70,7 @@
OptionEngine::optionEngine->addOptionGroup("Ultracopier",KeysList);
KeysList.clear();
- KeysList.push_back(std::pair("List","Ultracopier"));
+ KeysList.push_back(std::pair("List","Ultracopier-Spec"));
OptionEngine::optionEngine->addOptionGroup("CopyEngine",KeysList);
//load the GUI option
@@ -101,7 +103,7 @@
{
int returnCode;
QApplication ultracopierApplication(argc, argv);
- ultracopierApplication.setApplicationVersion(ULTRACOPIER_VERSION);
+ ultracopierApplication.setApplicationVersion(QString::fromStdString(FacilityEngine::version()));
ultracopierApplication.setQuitOnLastWindowClosed(false);
qRegisterMetaType("PluginsAvailable");
qRegisterMetaType("Ultracopier::DebugLevel");
diff -Nru ultracopier-1.6.1.3/OptionDialog.cpp ultracopier-2.2.4.4/OptionDialog.cpp
--- ultracopier-1.6.1.3/OptionDialog.cpp 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/OptionDialog.cpp 2010-01-01 04:00:00.000000000 +0000
@@ -8,13 +8,20 @@
#include "OSSpecific.h"
#include "LanguagesManager.h"
#include "cpp11addition.h"
+#include "FacilityEngine.h"
#include
#include
#include
+#ifndef NOAUDIO
+#include
+#endif
OptionDialog::OptionDialog() :
ui(new Ui::OptionDialog)
+ #ifndef NOAUDIO
+ ,buffer(&data)
+ #endif
{
quit=false;
QStringList ultracopierArguments=QCoreApplication::arguments();
@@ -27,8 +34,8 @@
oSSpecific=NULL;
ui->setupUi(this);
ui->treeWidget->topLevelItem(0)->setSelected(true);
- ui->treeWidget->topLevelItem(4)->setTextColor(0,QColor(150, 150, 150, 255));
- ui->treeWidget->topLevelItem(5)->setTextColor(0,QColor(150, 150, 150, 255));
+ ui->treeWidget->topLevelItem(4)->setForeground(0,QColor(150, 150, 150, 255));
+ ui->treeWidget->topLevelItem(5)->setForeground(0,QColor(150, 150, 150, 255));
ui->treeWidget->expandAll();
ui->pluginList->expandAll();
number_of_listener=0;
@@ -402,10 +409,12 @@
newOptionValue("Ultracopier", "ActionOnManualOpen", OptionEngine::optionEngine->getOptionValue("Ultracopier","ActionOnManualOpen"));
newOptionValue("Ultracopier", "GroupWindowWhen", OptionEngine::optionEngine->getOptionValue("Ultracopier","GroupWindowWhen"));
newOptionValue("Ultracopier", "confirmToGroupWindows", OptionEngine::optionEngine->getOptionValue("Ultracopier","confirmToGroupWindows"));
- newOptionValue("Ultracopier", "displayOSSpecific", OptionEngine::optionEngine->getOptionValue("Ultracopier","displayOSSpecific"));
+ newOptionValue("Ultracopier", "displayOSSpecific2", OptionEngine::optionEngine->getOptionValue("Ultracopier","displayOSSpecific2"));
newOptionValue("Ultracopier", "checkTheUpdate", OptionEngine::optionEngine->getOptionValue("Ultracopier","checkTheUpdate"));
newOptionValue("Ultracopier", "remainingTimeAlgorithm", OptionEngine::optionEngine->getOptionValue("Ultracopier","remainingTimeAlgorithm"));
newOptionValue("Ultracopier", "portable", OptionEngine::optionEngine->getOptionValue("Ultracopier","portable"));
+ newOptionValue("Ultracopier", "soundFile", OptionEngine::optionEngine->getOptionValue("Ultracopier","soundFile"));
+ newOptionValue("Ultracopier", "soundWhenFinish", OptionEngine::optionEngine->getOptionValue("Ultracopier","soundWhenFinish"));
newOptionValue("Language", "Language", OptionEngine::optionEngine->getOptionValue("Language","Language"));
newOptionValue("Language", "Language_force", OptionEngine::optionEngine->getOptionValue("Language","Language_force"));
#ifndef ULTRACOPIER_VERSION_PORTABLE
@@ -447,7 +456,7 @@
allPluginsIsLoaded=true;
on_Ultracopier_current_theme_currentIndexChanged(ui->Ultracopier_current_theme->currentIndex());
- if(stringtobool(OptionEngine::optionEngine->getOptionValue("Ultracopier","displayOSSpecific")))
+ if(stringtobool(OptionEngine::optionEngine->getOptionValue("Ultracopier","displayOSSpecific2")))
{
if(!quit)
{
@@ -463,7 +472,11 @@
if(oSSpecific==NULL)
return;
if(oSSpecific->dontShowAgain())
- OptionEngine::optionEngine->setOptionValue("Ultracopier","displayOSSpecific","false");
+ OptionEngine::optionEngine->setOptionValue("Ultracopier","displayOSSpecific2","false");
+ if(oSSpecific->theme()=="classic")
+ OptionEngine::optionEngine->setOptionValue("Themes","Ultracopier_current_theme","Oxygen");
+ else if(oSSpecific->theme()=="supercopier")
+ OptionEngine::optionEngine->setOptionValue("Themes","Ultracopier_current_theme","Supercopier");
delete oSSpecific;
oSSpecific=NULL;
}
@@ -585,10 +598,14 @@
ui->GroupWindowWhen->setCurrentIndex(stringtoint32(value));
else if(name=="confirmToGroupWindows")
ui->confirmToGroupWindows->setChecked(stringtobool(value));
- else if(name=="displayOSSpecific")
+ else if(name=="displayOSSpecific2")
ui->DisplayOSWarning->setChecked(stringtobool(value));
else if(name=="checkTheUpdate")
ui->checkTheUpdate->setChecked(stringtobool(value));
+ else if(name=="soundFile")
+ ui->soundFile->setText(QString::fromStdString(value));
+ else if(name=="soundWhenFinish")
+ ui->soundWhenFinish->setChecked(stringtobool(value));
else if(name=="remainingTimeAlgorithm")
{
bool ok;
@@ -984,7 +1001,7 @@
if(allPluginsIsLoaded)
{
ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start");
- OptionEngine::optionEngine->setOptionValue("Ultracopier","displayOSSpecific",booltostring(ui->DisplayOSWarning->isChecked()));
+ OptionEngine::optionEngine->setOptionValue("Ultracopier","displayOSSpecific2",booltostring(ui->DisplayOSWarning->isChecked()));
}
}
@@ -1036,3 +1053,40 @@
else
QFile::remove(settingsFilePath+"/Ultracopier.conf");
}
+
+void OptionDialog::on_soundFile_editingFinished()
+{
+ if(allPluginsIsLoaded)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start");
+ OptionEngine::optionEngine->setOptionValue("Ultracopier","soundFile",ui->soundFile->text().toStdString());
+ }
+}
+
+void OptionDialog::on_soundWhenFinish_toggled(bool checked)
+{
+ if(allPluginsIsLoaded)
+ {
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start");
+ OptionEngine::optionEngine->setOptionValue("Ultracopier","soundWhenFinish",std::to_string(checked));
+ }
+}
+
+void OptionDialog::on_playSound_clicked()
+{
+ #ifndef NOAUDIO
+ const std::string newSoundFile=ui->soundFile->text().toStdString();
+ buffer.seek(0);
+ data.clear();
+ if(!buffer.isOpen())
+ buffer.open(QIODevice::ReadWrite);
+ QAudioOutput *audio=static_cast(FacilityEngine::facilityEngine.prepareOpusAudio(newSoundFile,buffer));
+ if(audio!=nullptr)
+ {
+ buffer.seek(0);
+ audio->start(&buffer);
+ }
+ else
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"unable to open sound file: "+newSoundFile);
+ #endif
+}
diff -Nru ultracopier-1.6.1.3/OptionDialog.h ultracopier-2.2.4.4/OptionDialog.h
--- ultracopier-1.6.1.3/OptionDialog.h 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/OptionDialog.h 2010-01-01 04:00:00.000000000 +0000
@@ -11,6 +11,9 @@
#include
#include
#include
+#ifndef NOAUDIO
+#include
+#endif
#include "Environment.h"
#include "OSSpecific.h"
@@ -82,6 +85,9 @@
void oSSpecificClosed();
void on_remainingTimeAlgorithm_currentIndexChanged(int index);
void on_portable_toggled(bool);
+ void on_soundFile_editingFinished();
+ void on_soundWhenFinish_toggled(bool checked);
+ void on_playSound_clicked();
private:
bool quit;
Ui::OptionDialog *ui;
@@ -112,6 +118,10 @@
QTreeWidgetItem * treeWidgetItem;
OSSpecific *oSSpecific;
bool allPluginsIsLoaded;
+ #ifndef NOAUDIO
+ QByteArray data;
+ QBuffer buffer;
+ #endif
public slots:
void newThemeOptions(const std::string &name,QWidget* theNewOptionsWidget,bool isLoaded,bool havePlugin);
void newClientList(const std::vector &clientsList);
diff -Nru ultracopier-1.6.1.3/OptionDialog.ui ultracopier-2.2.4.4/OptionDialog.ui
--- ultracopier-1.6.1.3/OptionDialog.ui 2009-12-31 23:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/OptionDialog.ui 2010-01-01 04:00:00.000000000 +0000
@@ -6,7 +6,7 @@
0
0
- 779
+ 808
455
@@ -290,6 +290,37 @@
+ -
+
+
-
+
+
+ -
+
+
+ false
+
+
+ default: finish.opus
+
+
+
+ -
+
+
+ Play
+
+
+
+
+
+ -
+
+
+ Sound when finish
+
+
+
-
@@ -877,12 +908,12 @@
setEnabled(bool)
- 313
- 13
+ 301
+ 7
- 533
- 44
+ 252
+ 11
@@ -893,12 +924,12 @@
setEnabled(bool)
- 583
- 20
+ 301
+ 7
- 584
- 40
+ 300
+ 11
@@ -909,12 +940,12 @@
setEnabled(bool)
- 345
- 21
+ 301
+ 7
- 582
- 105
+ 301
+ 14
@@ -925,12 +956,12 @@
setEnabled(bool)
- 348
- 25
+ 301
+ 7
- 557
- 156
+ 301
+ 20
@@ -941,12 +972,12 @@
setEnabled(bool)
- 537
- 105
+ 301
+ 14
- 533
- 131
+ 301
+ 16
@@ -957,12 +988,12 @@
setEnabled(bool)
- 501
- 156
+ 301
+ 20
- 501
- 182
+ 301
+ 22
@@ -973,12 +1004,12 @@
setEnabled(bool)
- 269
- 15
+ 301
+ 7
- 456
- 207
+ 301
+ 27
@@ -989,12 +1020,28 @@
setEnabled(bool)
- 334
+ 301
+ 7
+
+
+ 301
12
+
+
+
+ soundWhenFinish
+ toggled(bool)
+ soundFile
+ setEnabled(bool)
+
+
+ 488
+ 337
+
- 304
- 69
+ 632
+ 346
diff -Nru ultracopier-1.6.1.3/opusfile/info.c ultracopier-2.2.4.4/opusfile/info.c
--- ultracopier-1.6.1.3/opusfile/info.c 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/opusfile/info.c 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,771 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include
+#include
+
+static unsigned op_parse_uint16le(const unsigned char *_data){
+ return _data[0]|_data[1]<<8;
+}
+
+static int op_parse_int16le(const unsigned char *_data){
+ int ret;
+ ret=_data[0]|_data[1]<<8;
+ return (ret^0x8000)-0x8000;
+}
+
+static opus_uint32 op_parse_uint32le(const unsigned char *_data){
+ return _data[0]|(opus_uint32)_data[1]<<8|
+ (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
+}
+
+static opus_uint32 op_parse_uint32be(const unsigned char *_data){
+ return _data[3]|(opus_uint32)_data[2]<<8|
+ (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
+}
+
+int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
+ OpusHead head;
+ if(_len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
+ if(_len<9)return OP_EBADHEADER;
+ head.version=_data[8];
+ if(head.version>15)return OP_EVERSION;
+ if(_len<19)return OP_EBADHEADER;
+ head.channel_count=_data[9];
+ head.pre_skip=op_parse_uint16le(_data+10);
+ head.input_sample_rate=op_parse_uint32le(_data+12);
+ head.output_gain=op_parse_int16le(_data+16);
+ head.mapping_family=_data[18];
+ if(head.mapping_family==0){
+ if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
+ if(head.version<=1&&_len>19)return OP_EBADHEADER;
+ head.stream_count=1;
+ head.coupled_count=head.channel_count-1;
+ if(_head!=NULL){
+ _head->mapping[0]=0;
+ _head->mapping[1]=1;
+ }
+ }
+ else if(head.mapping_family==1){
+ size_t size;
+ int ci;
+ if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
+ size=21+head.channel_count;
+ if(_lensize)return OP_EBADHEADER;
+ head.stream_count=_data[19];
+ if(head.stream_count<1)return OP_EBADHEADER;
+ head.coupled_count=_data[20];
+ if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
+ for(ci=0;ci=head.stream_count+head.coupled_count
+ &&_data[21+ci]!=255){
+ return OP_EBADHEADER;
+ }
+ }
+ if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
+ }
+ /*General purpose players should not attempt to play back content with
+ channel mapping family 255.*/
+ else if(head.mapping_family==255)return OP_EIMPL;
+ /*No other channel mapping families are currently defined.*/
+ else return OP_EBADHEADER;
+ if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
+ return 0;
+}
+
+void opus_tags_init(OpusTags *_tags){
+ memset(_tags,0,sizeof(*_tags));
+}
+
+void opus_tags_clear(OpusTags *_tags){
+ int ncomments;
+ int ci;
+ ncomments=_tags->comments;
+ if(_tags->user_comments!=NULL)ncomments++;
+ for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
+ _ogg_free(_tags->user_comments);
+ _ogg_free(_tags->comment_lengths);
+ _ogg_free(_tags->vendor);
+}
+
+/*Ensure there's room for up to _ncomments comments.*/
+static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
+ char **user_comments;
+ int *comment_lengths;
+ int cur_ncomments;
+ size_t size;
+ if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
+ size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
+ if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
+ cur_ncomments=_tags->comments;
+ /*We only support growing.
+ Trimming requires cleaning up the allocated strings in the old space, and
+ is best handled separately if it's ever needed.*/
+ OP_ASSERT(_ncomments>=(size_t)cur_ncomments);
+ comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
+ if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
+ if(_tags->comment_lengths==NULL){
+ OP_ASSERT(cur_ncomments==0);
+ comment_lengths[cur_ncomments]=0;
+ }
+ comment_lengths[_ncomments]=comment_lengths[cur_ncomments];
+ _tags->comment_lengths=comment_lengths;
+ size=sizeof(*_tags->user_comments)*(_ncomments+1);
+ if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
+ user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
+ if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
+ if(_tags->user_comments==NULL){
+ OP_ASSERT(cur_ncomments==0);
+ user_comments[cur_ncomments]=NULL;
+ }
+ user_comments[_ncomments]=user_comments[cur_ncomments];
+ _tags->user_comments=user_comments;
+ return 0;
+}
+
+/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
+static char *op_strdup_with_len(const char *_s,size_t _len){
+ size_t size;
+ char *ret;
+ size=sizeof(*ret)*(_len+1);
+ if(OP_UNLIKELY(size<_len))return NULL;
+ ret=(char *)_ogg_malloc(size);
+ if(OP_LIKELY(ret!=NULL)){
+ ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
+ ret[_len]='\0';
+ }
+ return ret;
+}
+
+/*The actual implementation of opus_tags_parse().
+ Unlike the public API, this function requires _tags to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_parse_impl(OpusTags *_tags,
+ const unsigned char *_data,size_t _len){
+ opus_uint32 count;
+ size_t len;
+ int ncomments;
+ int ci;
+ len=_len;
+ if(len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
+ if(len<16)return OP_EBADHEADER;
+ _data+=8;
+ len-=8;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ if(_tags!=NULL){
+ _tags->vendor=op_strdup_with_len((char *)_data,count);
+ if(_tags->vendor==NULL)return OP_EFAULT;
+ }
+ _data+=count;
+ len-=count;
+ if(len<4)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ /*Check to make sure there's minimally sufficient data left in the packet.*/
+ if(count>len>>2)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
+ if(_tags!=NULL){
+ int ret;
+ ret=op_tags_ensure_capacity(_tags,count);
+ if(ret<0)return ret;
+ }
+ ncomments=(int)count;
+ for(ci=0;cilen>>2)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
+ if(_tags!=NULL){
+ _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
+ if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
+ _tags->comment_lengths[ci]=(int)count;
+ _tags->comments=ci+1;
+ /*Needed by opus_tags_clear() if we fail before parsing the (optional)
+ binary metadata.*/
+ _tags->user_comments[ci+1]=NULL;
+ }
+ _data+=count;
+ len-=count;
+ }
+ if(len>0&&(_data[0]&1)){
+ if(len>(opus_uint32)INT_MAX)return OP_EFAULT;
+ if(_tags!=NULL){
+ _tags->user_comments[ncomments]=(char *)_ogg_malloc(len);
+ if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
+ memcpy(_tags->user_comments[ncomments],_data,len);
+ _tags->comment_lengths[ncomments]=(int)len;
+ }
+ }
+ return 0;
+}
+
+int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
+ if(_tags!=NULL){
+ OpusTags tags;
+ int ret;
+ opus_tags_init(&tags);
+ ret=opus_tags_parse_impl(&tags,_data,_len);
+ if(ret<0)opus_tags_clear(&tags);
+ else *_tags=*&tags;
+ return ret;
+ }
+ else return opus_tags_parse_impl(NULL,_data,_len);
+}
+
+/*The actual implementation of opus_tags_copy().
+ Unlike the public API, this function requires _dst to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
+ char *vendor;
+ int ncomments;
+ int ret;
+ int ci;
+ vendor=_src->vendor;
+ _dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
+ if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
+ ncomments=_src->comments;
+ ret=op_tags_ensure_capacity(_dst,ncomments);
+ if(OP_UNLIKELY(ret<0))return ret;
+ for(ci=0;cicomment_lengths[ci];
+ OP_ASSERT(len>=0);
+ _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
+ if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
+ _dst->comment_lengths[ci]=len;
+ _dst->comments=ci+1;
+ }
+ if(_src->comment_lengths!=NULL){
+ int len;
+ len=_src->comment_lengths[ncomments];
+ if(len>0){
+ _dst->user_comments[ncomments]=(char *)_ogg_malloc(len);
+ if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT;
+ memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len);
+ _dst->comment_lengths[ncomments]=len;
+ }
+ }
+ return 0;
+}
+
+int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
+ OpusTags dst;
+ int ret;
+ opus_tags_init(&dst);
+ ret=opus_tags_copy_impl(&dst,_src);
+ if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
+ else *_dst=*&dst;
+ return ret;
+}
+
+int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
+ char *comment;
+ size_t tag_len;
+ size_t value_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ tag_len=strlen(_tag);
+ value_len=strlen(_value);
+ /*+2 for '=' and '\0'.*/
+ if(tag_len+value_len(size_t)INT_MAX-2)return OP_EFAULT;
+ comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
+ if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
+ memcpy(comment,_tag,sizeof(*comment)*tag_len);
+ comment[tag_len]='=';
+ memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
+ _tags->user_comments[ncomments]=comment;
+ _tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1);
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
+ char *comment;
+ int comment_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ comment_len=(int)strlen(_comment);
+ comment=op_strdup_with_len(_comment,comment_len);
+ if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
+ _tags->user_comments[ncomments]=comment;
+ _tags->comment_lengths[ncomments]=comment_len;
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tags_set_binary_suffix(OpusTags *_tags,
+ const unsigned char *_data,int _len){
+ unsigned char *binary_suffix_data;
+ int ncomments;
+ int ret;
+ if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments);
+ if(OP_UNLIKELY(ret<0))return ret;
+ binary_suffix_data=
+ (unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len);
+ if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT;
+ memcpy(binary_suffix_data,_data,_len);
+ _tags->user_comments[ncomments]=(char *)binary_suffix_data;
+ _tags->comment_lengths[ncomments]=_len;
+ return 0;
+}
+
+int opus_tagcompare(const char *_tag_name,const char *_comment){
+ size_t tag_len;
+ tag_len=strlen(_tag_name);
+ if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1;
+ return opus_tagncompare(_tag_name,(int)tag_len,_comment);
+}
+
+int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
+ int ret;
+ OP_ASSERT(_tag_len>=0);
+ ret=op_strncasecmp(_tag_name,_comment,_tag_len);
+ return ret?ret:'='-_comment[_tag_len];
+}
+
+const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
+ char **user_comments;
+ size_t tag_len;
+ int found;
+ int ncomments;
+ int ci;
+ tag_len=strlen(_tag);
+ if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL;
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;ci(size_t)INT_MAX))return 0;
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;cicomments;
+ len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments];
+ *_len=len;
+ OP_ASSERT(len==0||_tags->user_comments!=NULL);
+ return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL;
+}
+
+static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
+ const char *_tag_name,size_t _tag_len){
+ char **comments;
+ int ncomments;
+ int ci;
+ comments=_tags->user_comments;
+ ncomments=_tags->comments;
+ /*Look for the first valid tag with the name _tag_name and use that.*/
+ for(ci=0;ci='0'&&*p<='9'){
+ gain_q8=10*gain_q8+*p-'0';
+ if(gain_q8>32767-negative)break;
+ p++;
+ }
+ /*This didn't look like a signed 16-bit decimal integer.
+ Not a valid gain tag.*/
+ if(*p!='\0')continue;
+ *_gain_q8=(int)(gain_q8+negative^negative);
+ return 0;
+ }
+ }
+ return OP_FALSE;
+}
+
+int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){
+ return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15);
+}
+
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
+ return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15);
+}
+
+static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ JPEG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_jpeg(_buf,_buf_sz)){
+ size_t offs;
+ offs=2;
+ for(;;){
+ size_t segment_len;
+ int marker;
+ while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
+ while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
+ marker=_buf[offs];
+ offs++;
+ /*If we hit EOI* (end of image), or another SOI* (start of image),
+ or SOS (start of scan), then stop now.*/
+ if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
+ /*RST* (restart markers): skip (no segment length).*/
+ else if(marker>=0xD0&&marker<=0xD7)continue;
+ /*Read the length of the marker segment.*/
+ if(_buf_sz-offs<2)break;
+ segment_len=_buf[offs]<<8|_buf[offs+1];
+ if(segment_len<2||_buf_sz-offs0xC0&&marker<0xD0&&(marker&3)!=0)){
+ /*Found a SOFn (start of frame) marker segment:*/
+ if(segment_len>=8){
+ *_height=_buf[offs+3]<<8|_buf[offs+4];
+ *_width=_buf[offs+5]<<8|_buf[offs+6];
+ *_depth=_buf[offs+2]*_buf[offs+7];
+ *_colors=0;
+ *_has_palette=0;
+ }
+ break;
+ }
+ /*Other markers: skip the whole marker segment.*/
+ offs+=segment_len;
+ }
+ }
+}
+
+static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ PNG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_png(_buf,_buf_sz)){
+ size_t offs;
+ offs=8;
+ while(_buf_sz-offs>=12){
+ ogg_uint32_t chunk_len;
+ chunk_len=op_parse_uint32be(_buf+offs);
+ if(chunk_len>_buf_sz-(offs+12))break;
+ else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
+ int color_type;
+ *_width=op_parse_uint32be(_buf+offs+8);
+ *_height=op_parse_uint32be(_buf+offs+12);
+ color_type=_buf[offs+17];
+ if(color_type==3){
+ *_depth=24;
+ *_has_palette=1;
+ }
+ else{
+ int sample_depth;
+ sample_depth=_buf[offs+16];
+ if(color_type==0)*_depth=sample_depth;
+ else if(color_type==2)*_depth=sample_depth*3;
+ else if(color_type==4)*_depth=sample_depth*2;
+ else if(color_type==6)*_depth=sample_depth*4;
+ *_colors=0;
+ *_has_palette=0;
+ break;
+ }
+ }
+ else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
+ *_colors=chunk_len/3;
+ break;
+ }
+ offs+=12+chunk_len;
+ }
+ }
+}
+
+static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ GIF.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
+ *_width=_buf[6]|_buf[7]<<8;
+ *_height=_buf[8]|_buf[9]<<8;
+ /*libFLAC hard-codes the depth to 24.*/
+ *_depth=24;
+ *_colors=1<<((_buf[10]&7)+1);
+ *_has_palette=1;
+ }
+}
+
+/*The actual implementation of opus_picture_tag_parse().
+ Unlike the public API, this function requires _pic to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
+ unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
+ opus_int32 picture_type;
+ opus_uint32 mime_type_length;
+ char *mime_type;
+ opus_uint32 description_length;
+ char *description;
+ opus_uint32 width;
+ opus_uint32 height;
+ opus_uint32 depth;
+ opus_uint32 colors;
+ opus_uint32 data_length;
+ opus_uint32 file_width;
+ opus_uint32 file_height;
+ opus_uint32 file_depth;
+ opus_uint32 file_colors;
+ int format;
+ int has_palette;
+ int colors_set;
+ size_t i;
+ /*Decode the BASE64 data.*/
+ for(i=0;i<_base64_sz;i++){
+ opus_uint32 value;
+ int j;
+ value=0;
+ for(j=0;j<4;j++){
+ unsigned c;
+ unsigned d;
+ c=(unsigned char)_tag[4*i+j];
+ if(c=='+')d=62;
+ else if(c=='/')d=63;
+ else if(c>='0'&&c<='9')d=52+c-'0';
+ else if(c>='a'&&c<='z')d=26+c-'a';
+ else if(c>='A'&&c<='Z')d=c-'A';
+ else if(c=='='&&3*i+j>_buf_sz)d=0;
+ else return OP_ENOTFORMAT;
+ value=value<<6|d;
+ }
+ _buf[3*i]=(unsigned char)(value>>16);
+ if(3*i+1<_buf_sz){
+ _buf[3*i+1]=(unsigned char)(value>>8);
+ if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
+ }
+ }
+ i=0;
+ picture_type=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*Extract the MIME type.*/
+ mime_type_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
+ mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
+ if(mime_type==NULL)return OP_EFAULT;
+ memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
+ mime_type[mime_type_length]='\0';
+ _pic->mime_type=mime_type;
+ i+=mime_type_length;
+ /*Extract the description string.*/
+ description_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
+ description=
+ (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
+ if(description==NULL)return OP_EFAULT;
+ memcpy(description,_buf+i,sizeof(*description)*description_length);
+ description[description_length]='\0';
+ _pic->description=description;
+ i+=description_length;
+ /*Extract the remaining fields.*/
+ width=op_parse_uint32be(_buf+i);
+ i+=4;
+ height=op_parse_uint32be(_buf+i);
+ i+=4;
+ depth=op_parse_uint32be(_buf+i);
+ i+=4;
+ colors=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*If one of these is set, they all must be, but colors==0 is a valid value.*/
+ colors_set=width!=0||height!=0||depth!=0||colors!=0;
+ if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
+ data_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
+ /*Trim extraneous data so we don't copy it below.*/
+ _buf_sz=i+data_length;
+ /*Attempt to determine the image format.*/
+ format=OP_PIC_FORMAT_UNKNOWN;
+ if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
+ format=OP_PIC_FORMAT_URL;
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ /*Append a terminating NUL for the convenience of our callers.*/
+ _buf[_buf_sz++]='\0';
+ }
+ else{
+ if(mime_type_length==10
+ &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
+ if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
+ if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ else if(mime_type_length==0||(mime_type_length==6
+ &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ file_width=file_height=file_depth=file_colors=0;
+ has_palette=-1;
+ switch(format){
+ case OP_PIC_FORMAT_JPEG:{
+ op_extract_jpeg_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_PNG:{
+ op_extract_png_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_GIF:{
+ op_extract_gif_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ }
+ if(has_palette>=0){
+ /*If we successfully extracted these parameters from the image, override
+ any declared values.*/
+ width=file_width;
+ height=file_height;
+ depth=file_depth;
+ colors=file_colors;
+ }
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ }
+ /*Adjust _buf_sz instead of using data_length to capture the terminating NUL
+ for URLs.*/
+ _buf_sz-=i;
+ memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
+ _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
+ if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
+ _pic->type=picture_type;
+ _pic->width=width;
+ _pic->height=height;
+ _pic->depth=depth;
+ _pic->colors=colors;
+ _pic->data_length=data_length;
+ _pic->data=_buf;
+ _pic->format=format;
+ return 0;
+}
+
+int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
+ OpusPictureTag pic;
+ unsigned char *buf;
+ size_t base64_sz;
+ size_t buf_sz;
+ size_t tag_length;
+ int ret;
+ if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
+ /*Figure out how much BASE64-encoded data we have.*/
+ tag_length=strlen(_tag);
+ if(tag_length&3)return OP_ENOTFORMAT;
+ base64_sz=tag_length>>2;
+ buf_sz=3*base64_sz;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ if(_tag[tag_length-1]=='=')buf_sz--;
+ if(_tag[tag_length-2]=='=')buf_sz--;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
+ buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
+ if(buf==NULL)return OP_EFAULT;
+ opus_picture_tag_init(&pic);
+ ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
+ if(ret<0){
+ opus_picture_tag_clear(&pic);
+ _ogg_free(buf);
+ }
+ else *_pic=*&pic;
+ return ret;
+}
+
+void opus_picture_tag_init(OpusPictureTag *_pic){
+ memset(_pic,0,sizeof(*_pic));
+}
+
+void opus_picture_tag_clear(OpusPictureTag *_pic){
+ _ogg_free(_pic->description);
+ _ogg_free(_pic->mime_type);
+ _ogg_free(_pic->data);
+}
diff -Nru ultracopier-1.6.1.3/opusfile/internal.c ultracopier-2.2.4.4/opusfile/internal.c
--- ultracopier-1.6.1.3/opusfile/internal.c 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/opusfile/internal.c 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,42 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+
+#if defined(OP_ENABLE_ASSERTIONS)
+void op_fatal_impl(const char *_str,const char *_file,int _line){
+ fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n",
+ _file,_line,_str);
+ abort();
+}
+#endif
+
+/*A version of strncasecmp() that is guaranteed to only ignore the case of
+ ASCII characters.*/
+int op_strncasecmp(const char *_a,const char *_b,int _n){
+ int i;
+ for(i=0;i<_n;i++){
+ int a;
+ int b;
+ int d;
+ a=_a[i];
+ b=_b[i];
+ if(a>='a'&&a<='z')a-='a'-'A';
+ if(b>='a'&&b<='z')b-='a'-'A';
+ d=a-b;
+ if(d)return d;
+ }
+ return 0;
+}
\ No newline at end of file
diff -Nru ultracopier-1.6.1.3/opusfile/internal.h ultracopier-2.2.4.4/opusfile/internal.h
--- ultracopier-1.6.1.3/opusfile/internal.h 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/opusfile/internal.h 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,259 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#if !defined(_opusfile_internal_h)
+# define _opusfile_internal_h (1)
+
+# if !defined(_REENTRANT)
+# define _REENTRANT
+# endif
+# if !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+# endif
+# if !defined(_LARGEFILE_SOURCE)
+# define _LARGEFILE_SOURCE
+# endif
+# if !defined(_LARGEFILE64_SOURCE)
+# define _LARGEFILE64_SOURCE
+# endif
+# if !defined(_FILE_OFFSET_BITS)
+# define _FILE_OFFSET_BITS 64
+# endif
+
+# include
+# include "opusfile.h"
+
+typedef struct OggOpusLink OggOpusLink;
+
+# if defined(OP_FIXED_POINT)
+
+typedef opus_int16 op_sample;
+
+# else
+
+typedef float op_sample;
+
+/*We're using this define to test for libopus 1.1 or later until libopus
+ provides a better mechanism.*/
+# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
+/*Enable soft clipping prevention in 16-bit decodes.*/
+# define OP_SOFT_CLIP (1)
+# endif
+
+# endif
+
+# if OP_GNUC_PREREQ(4,2)
+/*Disable excessive warnings about the order of operations.*/
+# pragma GCC diagnostic ignored "-Wparentheses"
+# elif defined(_MSC_VER)
+/*Disable excessive warnings about the order of operations.*/
+# pragma warning(disable:4554)
+/*Disable warnings about "deprecated" POSIX functions.*/
+# pragma warning(disable:4996)
+# endif
+
+# if OP_GNUC_PREREQ(3,0)
+/*Another alternative is
+ (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1))
+ but that evaluates _x multiple times, which may be bad.*/
+# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1))
+# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0))
+# else
+# define OP_LIKELY(_x) (!!(_x))
+# define OP_UNLIKELY(_x) (!!(_x))
+# endif
+
+# if defined(OP_ENABLE_ASSERTIONS)
+# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590
+__attribute__((noreturn))
+# endif
+void op_fatal_impl(const char *_str,const char *_file,int _line);
+
+# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__))
+
+# define OP_ASSERT(_cond) \
+ do{ \
+ if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \
+ } \
+ while(0)
+# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond)
+
+# else
+# define OP_FATAL(_str) abort()
+# define OP_ASSERT(_cond)
+# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
+# endif
+
+# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
+# define OP_INT64_MIN (-OP_INT64_MAX-1)
+# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
+# define OP_INT32_MIN (-OP_INT32_MAX-1)
+
+# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
+# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi)))
+
+/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
+ This is used to advance a known offset by things like OP_CHUNK_SIZE or
+ OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
+ It assumes that both _offset and _amount are non-negative.*/
+#define OP_ADV_OFFSET(_offset,_amount) \
+ (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
+
+/*The maximum channel count for any mapping we'll actually decode.*/
+# define OP_NCHANNELS_MAX (8)
+
+/*Initial state.*/
+# define OP_NOTOPEN (0)
+/*We've found the first Opus stream in the first link.*/
+# define OP_PARTOPEN (1)
+# define OP_OPENED (2)
+/*We've found the first Opus stream in the current link.*/
+# define OP_STREAMSET (3)
+/*We've initialized the decoder for the chosen Opus stream in the current
+ link.*/
+# define OP_INITSET (4)
+
+/*Information cached for a single link in a chained Ogg Opus file.
+ We choose the first Opus stream encountered in each link to play back (and
+ require at least one).*/
+struct OggOpusLink{
+ /*The byte offset of the first header page in this link.*/
+ opus_int64 offset;
+ /*The byte offset of the first data page from the chosen Opus stream in this
+ link (after the headers).*/
+ opus_int64 data_offset;
+ /*The byte offset of the last page from the chosen Opus stream in this link.
+ This is used when seeking to ensure we find a page before the last one, so
+ that end-trimming calculations work properly.
+ This is only valid for seekable sources.*/
+ opus_int64 end_offset;
+ /*The total duration of all prior links.
+ This is always zero for non-seekable sources.*/
+ ogg_int64_t pcm_file_offset;
+ /*The granule position of the last sample.
+ This is only valid for seekable sources.*/
+ ogg_int64_t pcm_end;
+ /*The granule position before the first sample.*/
+ ogg_int64_t pcm_start;
+ /*The serial number.*/
+ ogg_uint32_t serialno;
+ /*The contents of the info header.*/
+ OpusHead head;
+ /*The contents of the comment header.*/
+ OpusTags tags;
+};
+
+struct OggOpusFile{
+ /*The callbacks used to access the stream.*/
+ OpusFileCallbacks callbacks;
+ /*A FILE *, memory buffer, etc.*/
+ void *stream;
+ /*Whether or not we can seek with this stream.*/
+ int seekable;
+ /*The number of links in this chained Ogg Opus file.*/
+ int nlinks;
+ /*The cached information from each link in a chained Ogg Opus file.
+ If stream isn't seekable (e.g., it's a pipe), only the current link
+ appears.*/
+ OggOpusLink *links;
+ /*The number of serial numbers from a single link.*/
+ int nserialnos;
+ /*The capacity of the list of serial numbers from a single link.*/
+ int cserialnos;
+ /*Storage for the list of serial numbers from a single link.
+ This is a scratch buffer used when scanning the BOS pages at the start of
+ each link.*/
+ ogg_uint32_t *serialnos;
+ /*This is the current offset of the data processed by the ogg_sync_state.
+ After a seek, this should be set to the target offset so that we can track
+ the byte offsets of subsequent pages.
+ After a call to op_get_next_page(), this will point to the first byte after
+ that page.*/
+ opus_int64 offset;
+ /*The total size of this stream, or -1 if it's unseekable.*/
+ opus_int64 end;
+ /*Used to locate pages in the stream.*/
+ ogg_sync_state oy;
+ /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
+ int ready_state;
+ /*The current link being played back.*/
+ int cur_link;
+ /*The number of decoded samples to discard from the start of decoding.*/
+ opus_int32 cur_discard_count;
+ /*The granule position of the previous packet (current packet start time).*/
+ ogg_int64_t prev_packet_gp;
+ /*The stream offset of the most recent page with completed packets, or -1.
+ This is only needed to recover continued packet data in the seeking logic,
+ when we use the current position as one of our bounds, only to later
+ discover it was the correct starting point.*/
+ opus_int64 prev_page_offset;
+ /*The number of bytes read since the last bitrate query, including framing.*/
+ opus_int64 bytes_tracked;
+ /*The number of samples decoded since the last bitrate query.*/
+ ogg_int64_t samples_tracked;
+ /*Takes physical pages and welds them into a logical stream of packets.*/
+ ogg_stream_state os;
+ /*Re-timestamped packets from a single page.
+ Buffering these relies on the undocumented libogg behavior that ogg_packet
+ pointers remain valid until the next page is submitted to the
+ ogg_stream_state they came from.*/
+ ogg_packet op[255];
+ /*The index of the next packet to return.*/
+ int op_pos;
+ /*The total number of packets available.*/
+ int op_count;
+ /*Central working state for the packet-to-PCM decoder.*/
+ OpusMSDecoder *od;
+ /*The application-provided packet decode callback.*/
+ op_decode_cb_func decode_cb;
+ /*The application-provided packet decode callback context.*/
+ void *decode_cb_ctx;
+ /*The stream count used to initialize the decoder.*/
+ int od_stream_count;
+ /*The coupled stream count used to initialize the decoder.*/
+ int od_coupled_count;
+ /*The channel count used to initialize the decoder.*/
+ int od_channel_count;
+ /*The channel mapping used to initialize the decoder.*/
+ unsigned char od_mapping[OP_NCHANNELS_MAX];
+ /*The buffered data for one decoded packet.*/
+ op_sample *od_buffer;
+ /*The current position in the decoded buffer.*/
+ int od_buffer_pos;
+ /*The number of valid samples in the decoded buffer.*/
+ int od_buffer_size;
+ /*The type of gain offset to apply.
+ One of OP_HEADER_GAIN, OP_ALBUM_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
+ int gain_type;
+ /*The offset to apply to the gain.*/
+ opus_int32 gain_offset_q8;
+ /*Internal state for soft clipping and dithering float->short output.*/
+#if !defined(OP_FIXED_POINT)
+# if defined(OP_SOFT_CLIP)
+ float clip_state[OP_NCHANNELS_MAX];
+# endif
+ float dither_a[OP_NCHANNELS_MAX*4];
+ float dither_b[OP_NCHANNELS_MAX*4];
+ opus_uint32 dither_seed;
+ int dither_mute;
+ int dither_disabled;
+ /*The number of channels represented by the internal state.
+ This gets set to 0 whenever anything that would prevent state propagation
+ occurs (switching between the float/short APIs, or between the
+ stereo/multistream APIs).*/
+ int state_channel_count;
+#endif
+};
+
+int op_strncasecmp(const char *_a,const char *_b,int _n);
+
+#endif
diff -Nru ultracopier-1.6.1.3/opusfile/opusfile.c ultracopier-2.2.4.4/opusfile/opusfile.c
--- ultracopier-1.6.1.3/opusfile/opusfile.c 1970-01-01 00:00:00.000000000 +0000
+++ ultracopier-2.2.4.4/opusfile/opusfile.c 2010-01-01 04:00:00.000000000 +0000
@@ -0,0 +1,3326 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
+
+ ********************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "internal.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "opusfile.h"
+
+/*This implementation is largely based off of libvorbisfile.
+ All of the Ogg bits work roughly the same, though I have made some
+ "improvements" that have not been folded back there, yet.*/
+
+/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one
+ logical bitstream arranged end to end (the only form of Ogg multiplexing
+ supported by this library.
+ Grouping (parallel multiplexing) is not supported, except to the extent that
+ if there are multiple logical Ogg streams in a single link of the chain, we
+ will ignore all but the first Opus stream we find.*/
+
+/*An Ogg Opus file can be played beginning to end (streamed) without worrying
+ ahead of time about chaining (see opusdec from the opus-tools package).
+ If we have the whole file, however, and want random access
+ (seeking/scrubbing) or desire to know the total length/time of a file, we
+ need to account for the possibility of chaining.*/
+
+/*We can handle things a number of ways.
+ We can determine the entire bitstream structure right off the bat, or find
+ pieces on demand.
+ This library determines and caches structure for the entire bitstream, but
+ builds a virtual decoder on the fly when moving between links in the chain.*/
+
+/*There are also different ways to implement seeking.
+ Enough information exists in an Ogg bitstream to seek to sample-granularity
+ positions in the output.
+ Or, one can seek by picking some portion of the stream roughly in the desired
+ area if we only want coarse navigation through the stream.
+ We implement and expose both strategies.*/
+
+/*The maximum number of bytes in a page (including the page headers).*/
+#define OP_PAGE_SIZE_MAX (65307)
+/*The default amount to seek backwards per step when trying to find the
+ previous page.
+ This must be at least as large as the maximum size of a page.*/
+#define OP_CHUNK_SIZE (65536)
+/*The maximum amount to seek backwards per step when trying to find the
+ previous page.*/
+#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024)
+/*A smaller read size is needed for low-rate streaming.*/
+#define OP_READ_SIZE (2048)
+
+int op_test(OpusHead *_head,
+ const unsigned char *_initial_data,size_t _initial_bytes){
+ ogg_sync_state oy;
+ char *data;
+ int err;
+ /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg
+ page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel
+ mapping bytes).
+ It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value +
+ 19 Opus header bytes using channel mapping family 0).
+ If we don't have at least that much data, give up now.*/
+ if(_initial_bytes<47)return OP_FALSE;
+ /*Only proceed if we start with the magic OggS string.
+ This is to prevent us spending a lot of time allocating memory and looking
+ for Ogg pages in non-Ogg files.*/
+ if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT;
+ if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT;
+ ogg_sync_init(&oy);
+ data=ogg_sync_buffer(&oy,(long)_initial_bytes);
+ if(data!=NULL){
+ ogg_stream_state os;
+ ogg_page og;
+ int ret;
+ memcpy(data,_initial_data,_initial_bytes);
+ ogg_sync_wrote(&oy,(long)_initial_bytes);
+ ogg_stream_init(&os,-1);
+ err=OP_FALSE;
+ do{
+ ogg_packet op;
+ ret=ogg_sync_pageout(&oy,&og);
+ /*Ignore holes.*/
+ if(ret<0)continue;
+ /*Stop if we run out of data.*/
+ if(!ret)break;
+ ogg_stream_reset_serialno(&os,ogg_page_serialno(&og));
+ ogg_stream_pagein(&os,&og);
+ /*Only process the first packet on this page (if it's a BOS packet,
+ it's required to be the only one).*/
+ if(ogg_stream_packetout(&os,&op)==1){
+ if(op.b_o_s){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*If this didn't look like Opus, keep going.*/
+ if(ret==OP_ENOTFORMAT)continue;
+ /*Otherwise we're done, one way or another.*/
+ err=ret;
+ }
+ /*We finished parsing the headers.
+ There is no Opus to be found.*/
+ else err=OP_ENOTFORMAT;
+ }
+ }
+ while(err==OP_FALSE);
+ ogg_stream_clear(&os);
+ }
+ else err=OP_EFAULT;
+ ogg_sync_clear(&oy);
+ return err;
+}
+
+/*Many, many internal helpers.
+ The intention is not to be confusing.
+ Rampant duplication and monolithic function implementation (though we do have
+ some large, omnibus functions still) would be harder to understand anyway.
+ The high level functions are last.
+ Begin grokking near the end of the file if you prefer to read things
+ top-down.*/
+
+/*The read/seek functions track absolute position within the stream.*/
+
+/*Read a little more data from the file/pipe into the ogg_sync framer.
+ _nbytes: The maximum number of bytes to read.
+ Return: A positive number of bytes read on success, 0 on end-of-file, or a
+ negative value on failure.*/
+static int op_get_data(OggOpusFile *_of,int _nbytes){
+ unsigned char *buffer;
+ int nbytes;
+ OP_ASSERT(_nbytes>0);
+ buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes);
+ nbytes=(int)(*_of->callbacks.read)(_of->stream,buffer,_nbytes);
+ OP_ASSERT(nbytes<=_nbytes);
+ if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes);
+ return nbytes;
+}
+
+/*Save a tiny smidge of verbosity to make the code more readable.*/
+static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
+ if(_offset==_of->offset)return 0;
+ if(_of->callbacks.seek==NULL
+ ||(*_of->callbacks.seek)(_of->stream,_offset,SEEK_SET)){
+ return OP_EREAD;
+ }
+ _of->offset=_offset;
+ ogg_sync_reset(&_of->oy);
+ return 0;
+}
+
+/*Get the current position indicator of the underlying stream.
+ This should be the same as the value reported by tell().*/
+static opus_int64 op_position(const OggOpusFile *_of){
+ /*The current position indicator is _not_ simply offset.
+ We may also have unprocessed, buffered data in the sync state.*/
+ return _of->offset+_of->oy.fill-_of->oy.returned;
+}
+
+/*From the head of the stream, get the next page.
+ _boundary specifies if the function is allowed to fetch more data from the
+ stream (and how much) or only use internally buffered data.
+ _boundary: -1: Unbounded search.
+ 0: Read no additional data.
+ Use only cached data.
+ n: Search for the start of a new page up to file position n.
+ Return: n>=0: Found a page at absolute offset n.
+ OP_FALSE: Hit the _boundary limit.
+ OP_EREAD: An underlying read operation failed.
+ OP_BADLINK: We hit end-of-file before reaching _boundary.*/
+static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og,
+ opus_int64 _boundary){
+ while(_boundary<=0||_of->offset<_boundary){
+ int more;
+ more=ogg_sync_pageseek(&_of->oy,_og);
+ /*Skipped (-more) bytes.*/
+ if(OP_UNLIKELY(more<0))_of->offset-=more;
+ else if(more==0){
+ int read_nbytes;
+ int ret;
+ /*Send more paramedics.*/
+ if(!_boundary)return OP_FALSE;
+ if(_boundary<0)read_nbytes=OP_READ_SIZE;
+ else{
+ opus_int64 position;
+ position=op_position(_of);
+ if(position>=_boundary)return OP_FALSE;
+ read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE);
+ }
+ ret=op_get_data(_of,read_nbytes);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ if(OP_UNLIKELY(ret==0)){
+ /*Only fail cleanly on EOF if we didn't have a known boundary.
+ Otherwise, we should have been able to reach that boundary, and this
+ is a fatal error.*/
+ return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK;
+ }
+ }
+ else{
+ /*Got a page.
+ Return the page start offset and advance the internal offset past the
+ page end.*/
+ opus_int64 page_offset;
+ page_offset=_of->offset;
+ _of->offset+=more;
+ OP_ASSERT(page_offset>=0);
+ return page_offset;
+ }
+ }
+ return OP_FALSE;
+}
+
+static int op_add_serialno(const ogg_page *_og,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ int cserialnos;
+ ogg_uint32_t s;
+ s=ogg_page_serialno(_og);
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ cserialnos=*_cserialnos;
+ if(OP_UNLIKELY(nserialnos>=cserialnos)){
+ if(OP_UNLIKELY(cserialnos>INT_MAX/(int)sizeof(*serialnos)-1>>1)){
+ return OP_EFAULT;
+ }
+ cserialnos=2*cserialnos+1;
+ OP_ASSERT(nserialnos=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ search_start=begin;
+ while(_of->offsetsearch_start=search_start;
+ _sr->offset=_offset=llret;
+ _sr->serialno=serialno;
+ OP_ASSERT(_of->offset-_offset>=0);
+ OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX);
+ _sr->size=(opus_int32)(_of->offset-_offset);
+ _sr->gp=ogg_page_granulepos(&og);
+ /*If this page is from the stream we're looking for, remember it.*/
+ if(serialno==_serialno){
+ preferred_found=1;
+ *&preferred_sr=*_sr;
+ }
+ if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){
+ /*We fell off the end of the link, which means we seeked back too far
+ and shouldn't have been looking in that link to begin with.
+ If we found the preferred serial number, forget that we saw it.*/
+ preferred_found=0;
+ }
+ search_start=llret+1;
+ }
+ /*We started from the beginning of the stream and found nothing.
+ This should be impossible unless the contents of the stream changed out
+ from under us after we read from it.*/
+ if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK;
+ /*Bump up the chunk size.
+ This is mildly helpful when seeks are very expensive (http).*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*Avoid quadratic complexity if we hit an invalid patch of the file.*/
+ end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end);
+ }
+ while(_offset<0);
+ if(preferred_found)*_sr=*&preferred_sr;
+ return 0;
+}
+
+/*Find the last page beginning before _offset with the given serial number and
+ a valid granule position.
+ Unlike the above search, this continues until it finds such a page, but does
+ not stray outside the current link.
+ We could implement it (inefficiently) by calling op_get_prev_page_serial()
+ repeatedly until it returned a page that had both our preferred serial
+ number and a valid granule position, but doing it with a separate function
+ allows us to avoid repeatedly re-scanning valid pages from other streams as
+ we seek-back-and-read-forward.
+ [out] _gp: Returns the granule position of the page that was found on
+ success.
+ _offset: The _offset before which to find a page.
+ Any page returned will consist of data entirely before _offset.
+ _serialno: The target serial number.
+ _serialnos: The list of serial numbers in the link that contains the
+ preferred serial number.
+ _nserialnos: The number of serial numbers in the current link.
+ Return: The offset of the page on success, or a negative value on failure.
+ OP_EREAD: Failed to read more data (error or EOF).
+ OP_EBADLINK: We couldn't find a page even after seeking back past the
+ beginning of the link.*/
+static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp,
+ opus_int64 _offset,ogg_uint32_t _serialno,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ ogg_page og;
+ ogg_int64_t gp;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 original_end;
+ opus_int32 chunk_size;
+ /*The target serial number must belong to the current link.*/
+ OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos));
+ original_end=end=begin=_offset;
+ _offset=-1;
+ /*We shouldn't have to initialize gp, but gcc is too dumb to figure out that
+ ret>=0 implies we entered the if(page_gp!=-1) block at least once.*/
+ gp=-1;
+ chunk_size=OP_CHUNK_SIZE;
+ do{
+ int left_link;
+ int ret;
+ OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ left_link=0;
+ while(_of->offsetready_stateos,ogg_page_serialno(_og));
+ ogg_stream_pagein(&_of->os,_og);
+ if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*Found a valid Opus header.
+ Continue setup.*/
+ if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET;
+ /*If it's just a stream type we don't recognize, ignore it.
+ Everything else is fatal.*/
+ else if(ret!=OP_ENOTFORMAT)return ret;
+ }
+ /*TODO: Should a BOS page with no packets be an error?*/
+ }
+ /*Get the next page.
+ No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT or OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return _of->ready_stateready_state!=OP_STREAMSET))return OP_ENOTFORMAT;
+ /*If the first non-header page belonged to our Opus stream, submit it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og);
+ /*Loop getting packets.*/
+ for(;;){
+ switch(ogg_stream_packetout(&_of->os,&op)){
+ case 0:{
+ /*Loop getting pages.*/
+ for(;;){
+ /*No need to clamp the boundary offset against _of->end, as all
+ errors become OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_EBADHEADER;
+ }
+ /*If this page belongs to the correct stream, go parse it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og)){
+ ogg_stream_pagein(&_of->os,_og);
+ break;
+ }
+ /*If the link ends before we see the Opus comment header, abort.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER;
+ /*Otherwise, keep looking.*/
+ }
+ }break;
+ /*We shouldn't get a hole in the headers!*/
+ case -1:return OP_EBADHEADER;
+ default:{
+ /*Got a packet.
+ It should be the comment header.*/
+ ret=opus_tags_parse(_tags,op.packet,op.bytes);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Make sure the page terminated at the end of the comment header.
+ If there is another packet on the page, or part of a packet, then
+ reject the stream.
+ Otherwise seekable sources won't be able to seek back to the start
+ properly.*/
+ ret=ogg_stream_packetout(&_of->os,&op);
+ if(OP_UNLIKELY(ret!=0)
+ ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){
+ /*If we fail, the caller assumes our tags are uninitialized.*/
+ opus_tags_clear(_tags);
+ return OP_EBADHEADER;
+ }
+ return 0;
+ }
+ }
+ }
+}
+
+static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head,
+ OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos,
+ int *_cserialnos,ogg_page *_og){
+ ogg_page og;
+ int ret;
+ if(!_og){
+ /*No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,&og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_ENOTFORMAT;
+ }
+ _og=&og;
+ }
+ _of->ready_state=OP_OPENED;
+ ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos,
+ _cserialnos,_og);
+ /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent
+ double-free of the tags in an unseekable stream.*/
+ if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED;
+ return ret;
+}
+
+/*Granule position manipulation routines.
+ A granule position is defined to be an unsigned 64-bit integer, with the
+ special value -1 in two's complement indicating an unset or invalid granule
+ position.
+ We are not guaranteed to have an unsigned 64-bit type, so we construct the
+ following routines that
+ a) Properly order negative numbers as larger than positive numbers, and
+ b) Check for underflow or overflow past the special -1 value.
+ This lets us operate on the full, valid range of granule positions in a
+ consistent and safe manner.
+ This full range is organized into distinct regions:
+ [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ]
+
+ No one should actually use granule positions so large that they're negative,
+ even if they are technically valid, as very little software handles them
+ correctly (including most of Xiph.Org's).
+ This library also refuses to support durations so large they won't fit in a
+ signed 64-bit integer (to avoid exposing this mess to the application, and
+ to simplify a good deal of internal arithmetic), so the only way to use them
+ successfully is if pcm_start is very large.
+ This means there isn't anything you can do with negative granule positions
+ that you couldn't have done with purely non-negative ones.
+ The main purpose of these routines is to allow us to think very explicitly
+ about the possible failure cases of all granule position manipulations.*/
+
+/*Safely adds a small signed integer to a valid (not -1) granule position.
+ The result can use the full 64-bit range of values (both positive and
+ negative), but will fail on overflow (wrapping past -1; wrapping past
+ OP_INT64_MAX is explicitly okay).
+ [out] _dst_gp: The resulting granule position.
+ Only modified on success.
+ _src_gp: The granule position to add to.
+ This must not be -1.
+ _delta: The amount to add.
+ This is allowed to be up to 32 bits to support the maximum
+ duration of a single Ogg page (255 packets * 120 ms per
+ packet == 1,468,800 samples at 48 kHz).
+ Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/
+static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp,
+ opus_int32 _delta){
+ /*The code below handles this case correctly, but there's no reason we
+ should ever be called with these values, so make sure we aren't.*/
+ OP_ASSERT(_src_gp!=-1);
+ if(_delta>0){
+ /*Adding this amount to the granule position would overflow its 64-bit
+ range.*/
+ if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){
+ /*Adding this amount to the granule position would overflow the positive
+ half of its 64-bit range.
+ Since signed overflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1;
+ _src_gp=OP_INT64_MIN;
+ }
+ }
+ else if(_delta<0){
+ /*Subtracting this amount from the granule position would underflow its
+ 64-bit range.*/
+ if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp da < 0.*/
+ da=(OP_INT64_MIN-_gp_a)-1;
+ /*_gp_b >= 0 => db >= 0.*/
+ db=OP_INT64_MAX-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(OP_INT64_MAX+da= 0 => da <= 0*/
+ da=_gp_a+OP_INT64_MIN;
+ /*_gp_b < 0 => db <= 0*/
+ db=OP_INT64_MIN-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(da=0)return 1;
+ /*Else fall through.*/
+ }
+ else if(OP_UNLIKELY(_gp_b<0))return -1;
+ /*No wrapping case.*/
+ return (_gp_a>_gp_b)-(_gp_b>_gp_a);
+}
+
+/*Returns the duration of the packet (in samples at 48 kHz), or a negative
+ value on error.*/
+static int op_get_packet_duration(const unsigned char *_data,int _len){
+ int nframes;
+ int frame_size;
+ int nsamples;
+ nframes=opus_packet_get_nb_frames(_data,_len);
+ if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET;
+ frame_size=opus_packet_get_samples_per_frame(_data,48000);
+ nsamples=nframes*frame_size;
+ if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET;
+ return nsamples;
+}
+
+/*This function more properly belongs in info.c, but we define it here to allow
+ the static granule position manipulation functions to remain static.*/
+ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){
+ opus_int32 pre_skip;
+ pre_skip=_head->pre_skip;
+ if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1;
+ return _gp;
+}
+
+/*Grab all the packets currently in the stream state, and compute their
+ durations.
+ _of->op_count is set to the number of packets collected.
+ [out] _durations: Returns the durations of the individual packets.
+ Return: The total duration of all packets, or OP_HOLE if there was a hole.*/
+static opus_int32 op_collect_audio_packets(OggOpusFile *_of,
+ int _durations[255]){
+ opus_int32 total_duration;
+ int op_count;
+ /*Count the durations of all packets in the page.*/
+ op_count=0;
+ total_duration=0;
+ for(;;){
+ int ret;
+ /*This takes advantage of undocumented libogg behavior that returned
+ ogg_packet buffers are valid at least until the next page is
+ submitted.
+ Relying on this is not too terrible, as _none_ of the Ogg memory
+ ownership/lifetime rules are well-documented.
+ But I can read its code and know this will work.*/
+ ret=ogg_stream_packetout(&_of->os,_of->op+op_count);
+ if(!ret)break;
+ if(OP_UNLIKELY(ret<0)){
+ /*We shouldn't get holes in the middle of pages.*/
+ OP_ASSERT(op_count==0);
+ /*Set the return value and break out of the loop.
+ We want to make sure op_count gets set to 0, because we've ingested a
+ page, so any previously loaded packets are now invalid.*/
+ total_duration=OP_HOLE;
+ break;
+ }
+ /*Unless libogg is broken, we can't get more than 255 packets from a
+ single page.*/
+ OP_ASSERT(op_count<255);
+ _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet,
+ _of->op[op_count].bytes);
+ if(OP_LIKELY(_durations[op_count]>0)){
+ /*With at most 255 packets on a page, this can't overflow.*/
+ total_duration+=_durations[op_count++];
+ }
+ /*Ignore packets with an invalid TOC sequence.*/
+ else if(op_count>0){
+ /*But save the granule position, if there was one.*/
+ _of->op[op_count-1].granulepos=_of->op[op_count].granulepos;
+ }
+ }
+ _of->op_pos=0;
+ _of->op_count=op_count;
+ return total_duration;
+}
+
+/*Starting from current cursor position, get the initial PCM offset of the next
+ page.
+ This also validates the granule position on the first page with a completed
+ audio data packet, as required by the spec.
+ If this link is completely empty (no pages with completed packets), then this
+ function sets pcm_start=pcm_end=0 and returns the BOS page of the next link
+ (if any).
+ In the seekable case, we initialize pcm_end=-1 before calling this function,
+ so that later we can detect that the link was empty before calling
+ op_find_final_pcm_offset().
+ [inout] _link: The link for which to find pcm_start.
+ [out] _og: Returns the BOS page of the next link if this link was empty.
+ In the unseekable case, we can then feed this to
+ op_fetch_headers() to start the next link.
+ The caller may pass NULL (e.g., for seekable streams), in
+ which case this page will be discarded.
+ Return: 0 on success, 1 if there is a buffered BOS page available, or a
+ negative value on unrecoverable error.*/
+static int op_find_initial_pcm_offset(OggOpusFile *_of,
+ OggOpusLink *_link,ogg_page *_og){
+ ogg_page og;
+ opus_int64 page_offset;
+ ogg_int64_t pcm_start;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t cur_page_gp;
+ ogg_uint32_t serialno;
+ opus_int32 total_duration;
+ int durations[255];
+ int cur_page_eos;
+ int op_count;
+ int pi;
+ if(_og==NULL)_og=&og;
+ serialno=_of->os.serialno;
+ op_count=0;
+ /*We shouldn't have to initialize total_duration, but gcc is too dumb to
+ figure out that op_count>0 implies we've been through the whole loop at
+ least once.*/
+ total_duration=0;
+ do{
+ page_offset=op_get_next_page(_of,_og,_of->end);
+ /*We should get a page unless the file is truncated or mangled.
+ Otherwise there are no audio data packets in the whole logical stream.*/
+ if(OP_UNLIKELY(page_offset<0)){
+ /*Fail if there was a read error.*/
+ if(page_offsethead.pre_skip>0)return OP_EBADTIMESTAMP;
+ _link->pcm_file_offset=0;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_start=_link->pcm_end=0;
+ _link->end_offset=_link->data_offset;
+ return 0;
+ }
+ /*Similarly, if we hit the next link in the chain, we've gone too far.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og))){
+ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_file_offset=0;
+ _link->pcm_start=_link->pcm_end=0;
+ _link->end_offset=_link->data_offset;
+ /*Tell the caller we've got a buffered page for them.*/
+ return 1;
+ }
+ /*Ignore pages from other streams (not strictly necessary, because of the
+ checks in ogg_stream_pagein(), but saves some work).*/
+ if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue;
+ ogg_stream_pagein(&_of->os,_og);
+ /*Bitrate tracking: add the header's bytes here.
+ The body bytes are counted when we consume the packets.*/
+ _of->bytes_tracked+=_og->header_len;
+ /*Count the durations of all packets in the page.*/
+ do total_duration=op_collect_audio_packets(_of,durations);
+ /*Ignore holes.*/
+ while(OP_UNLIKELY(total_duration<0));
+ op_count=_of->op_count;
+ }
+ while(op_count<=0);
+ /*We found the first page with a completed audio data packet: actually look
+ at the granule position.
+ RFC 3533 says, "A special value of -1 (in two's complement) indicates that
+ no packets finish on this page," which does not say that a granule
+ position that is NOT -1 indicates that some packets DO finish on that page
+ (even though this was the intention, libogg itself violated this intention
+ for years before we fixed it).
+ The Ogg Opus specification only imposes its start-time requirements
+ on the granule position of the first page with completed packets,
+ so we ignore any set granule positions until then.*/
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ /*But getting a packet without a valid granule position on the page is not
+ okay.*/
+ if(cur_page_gp==-1)return OP_EBADTIMESTAMP;
+ cur_page_eos=_of->op[op_count-1].e_o_s;
+ if(OP_LIKELY(!cur_page_eos)){
+ /*The EOS flag wasn't set.
+ Work backwards from the provided granule position to get the starting PCM
+ offset.*/
+ if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*The starting granule position MUST not be smaller than the amount of
+ audio on the first page with completed packets.*/
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ else{
+ /*The first page with completed packets was also the last.*/
+ if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*If there's less audio on the page than indicated by the granule
+ position, then we're doing end-trimming, and the starting PCM offset
+ is zero by spec mandate.*/
+ pcm_start=0;
+ /*However, the end-trimming MUST not ask us to trim more samples than
+ exist after applying the pre-skip.*/
+ if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ }
+ /*Timestamp the individual packets.*/
+ prev_packet_gp=pcm_start;
+ for(pi=0;pi0){
+ /*If we trimmed the entire packet, stop (the spec says encoders
+ shouldn't do this, but we support it anyway).*/
+ if(OP_UNLIKELY(diff>durations[pi]))break;
+ _of->op[pi].granulepos=prev_packet_gp=cur_page_gp;
+ /*Move the EOS flag to this packet, if necessary, so we'll trim the
+ samples.*/
+ _of->op[pi].e_o_s=1;
+ continue;
+ }
+ }
+ /*Update the granule position as normal.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos,
+ prev_packet_gp,durations[pi]));
+ prev_packet_gp=_of->op[pi].granulepos;
+ }
+ /*Update the packet count after end-trimming.*/
+ _of->op_count=pi;
+ _of->cur_discard_count=_link->head.pre_skip;
+ _link->pcm_file_offset=0;
+ _of->prev_packet_gp=_link->pcm_start=pcm_start;
+ _of->prev_page_offset=page_offset;
+ return 0;
+}
+
+/*Starting from current cursor position, get the final PCM offset of the
+ previous page.
+ This also validates the duration of the link, which, while not strictly
+ required by the spec, we need to ensure duration calculations don't
+ overflow.
+ This is only done for seekable sources.
+ We must validate that op_find_initial_pcm_offset() succeeded for this link
+ before calling this function, otherwise it will scan the entire stream
+ backwards until it reaches the start, and then fail.*/
+static int op_find_final_pcm_offset(OggOpusFile *_of,
+ const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link,
+ opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp,
+ ogg_int64_t *_total_duration){
+ ogg_int64_t total_duration;
+ ogg_int64_t duration;
+ ogg_uint32_t cur_serialno;
+ /*For the time being, fetch end PCM offset the simple way.*/
+ cur_serialno=_link->serialno;
+ if(_end_serialno!=cur_serialno||_end_gp==-1){
+ _offset=op_get_last_page(_of,&_end_gp,_offset,
+ cur_serialno,_serialnos,_nserialnos);
+ if(OP_UNLIKELY(_offset<0))return (int)_offset;
+ }
+ /*At worst we should have found the first page with completed packets.*/
+ if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK;
+ /*This implementation requires that the difference between the first and last
+ granule positions in each link be representable in a signed, 64-bit
+ number, and that each link also have at least as many samples as the
+ pre-skip requires.*/
+ if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0)
+ ||OP_UNLIKELY(duration<_link->head.pre_skip)){
+ return OP_EBADTIMESTAMP;
+ }
+ /*We also require that the total duration be representable in a signed,
+ 64-bit number.*/
+ duration-=_link->head.pre_skip;
+ total_duration=*_total_duration;
+ if(OP_UNLIKELY(OP_INT64_MAX-durationpcm_end=_end_gp;
+ _link->end_offset=_offset;
+ return 0;
+}
+
+/*Rescale the number _x from the range [0,_from] to [0,_to].
+ _from and _to must be positive.*/
+static opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){
+ opus_int64 frac;
+ opus_int64 ret;
+ int i;
+ if(_x>=_from)return _to;
+ if(_x<=0)return 0;
+ frac=0;
+ for(i=0;i<63;i++){
+ frac<<=1;
+ OP_ASSERT(_x<=_from);
+ if(_x>=_from>>1){
+ _x-=_from-_x;
+ frac|=1;
+ }
+ else _x<<=1;
+ }
+ ret=0;
+ for(i=0;i<63;i++){
+ if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1);
+ else ret>>=1;
+ frac>>=1;
+ }
+ return ret;
+}
+
+/*The minimum granule position spacing allowed for making predictions.
+ This corresponds to about 1 second of audio at 48 kHz for both Opus and
+ Vorbis, or one keyframe interval in Theora with the default keyframe spacing
+ of 256.*/
+#define OP_GP_SPACING_MIN (48000)
+
+/*Try to estimate the location of the next link using the current seek
+ records, assuming the initial granule position of any streams we've found is
+ 0.*/
+static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr,
+ opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){
+ opus_int64 bisect;
+ int sri;
+ int srj;
+ /*Require that we be at least OP_CHUNK_SIZE from the end.
+ We don't require that we be at least OP_CHUNK_SIZE from the beginning,
+ because if we are we'll just scan forward without seeking.*/
+ _end_searched-=OP_CHUNK_SIZE;
+ if(_searched>=_end_searched)return -1;
+ bisect=_end_searched;
+ for(sri=0;sri<_nsr;sri++){
+ ogg_int64_t gp1;
+ ogg_int64_t gp2_min;
+ ogg_uint32_t serialno1;
+ opus_int64 offset1;
+ /*If the granule position is negative, either it's invalid or we'd cause
+ overflow.*/
+ gp1=_sr[sri].gp;
+ if(gp1<0)continue;
+ /*We require some minimum distance between granule positions to make an
+ estimate.
+ We don't actually know what granule position scheme is being used,
+ because we have no idea what kind of stream these came from.
+ Therefore we require a minimum spacing between them, with the
+ expectation that while bitrates and granule position increments might
+ vary locally in quite complex ways, they are globally smooth.*/
+ if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){
+ /*No granule position would satisfy us.*/
+ continue;
+ }
+ offset1=_sr[sri].offset;
+ serialno1=_sr[sri].serialno;
+ for(srj=sri;srj-->0;){
+ ogg_int64_t gp2;
+ opus_int64 offset2;
+ opus_int64 num;
+ ogg_int64_t den;
+ ogg_int64_t ipart;
+ gp2=_sr[srj].gp;
+ if(gp20);
+ if(ipart>0&&(offset2-_searched)/ipart=_end_searched?-1:bisect;
+}
+
+/*Finds each bitstream link, one at a time, using a bisection search.
+ This has to begin by knowing the offset of the first link's initial page.*/
+static int op_bisect_forward_serialno(OggOpusFile *_of,
+ opus_int64 _searched,OpusSeekRecord *_sr,int _csr,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_page og;
+ OggOpusLink *links;
+ int nlinks;
+ int clinks;
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ ogg_int64_t total_duration;
+ int nsr;
+ int ret;
+ links=_of->links;
+ nlinks=clinks=_of->nlinks;
+ total_duration=0;
+ /*We start with one seek record, for the last page in the file.
+ We build up a list of records for places we seek to during link
+ enumeration.
+ This list is kept sorted in reverse order.
+ We only care about seek locations that were _not_ in the current link,
+ therefore we can add them one at a time to the end of the list as we
+ improve the lower bound on the location where the next link starts.*/
+ nsr=1;
+ for(;;){
+ opus_int64 end_searched;
+ opus_int64 bisect;
+ opus_int64 next;
+ opus_int64 last;
+ ogg_int64_t end_offset;
+ ogg_int64_t end_gp;
+ int sri;
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ if(OP_UNLIKELY(nlinks>=clinks)){
+ if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT;
+ clinks=2*clinks+1;
+ OP_ASSERT(nlinkslinks=links;
+ }
+ /*Invariants:
+ We have the headers and serial numbers for the link beginning at 'begin'.
+ We have the offset and granule position of the last page in the file
+ (potentially not a page we care about).*/
+ /*Scan the seek records we already have to save us some bisection.*/
+ for(sri=0;sri1){
+ opus_int64 last_offset;
+ opus_int64 avg_link_size;
+ opus_int64 upper_limit;
+ last_offset=links[nlinks-1].offset;
+ avg_link_size=last_offset/(nlinks-1);
+ upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size;
+ if(OP_LIKELY(last_offset>_searched-avg_link_size)
+ &&OP_LIKELY(last_offset>1);
+ /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/
+ if(bisect-_searched