Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
0248a7fc
Commit
0248a7fc
authored
Nov 19, 2012
by
Francois Cartegnie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chromaprint: add fingerprinter module
parent
27431a57
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1673 additions
and
0 deletions
+1673
-0
modules/LIST
modules/LIST
+1
-0
modules/misc/Modules.am
modules/misc/Modules.am
+7
-0
modules/misc/fingerprinter.c
modules/misc/fingerprinter.c
+415
-0
modules/misc/webservices/acoustid.c
modules/misc/webservices/acoustid.c
+229
-0
modules/misc/webservices/acoustid.h
modules/misc/webservices/acoustid.h
+59
-0
modules/misc/webservices/json.c
modules/misc/webservices/json.c
+739
-0
modules/misc/webservices/json.h
modules/misc/webservices/json.h
+34
-0
modules/misc/webservices/use_json.h
modules/misc/webservices/use_json.h
+189
-0
No files found.
modules/LIST
View file @
0248a7fc
...
@@ -124,6 +124,7 @@ $Id$
...
@@ -124,6 +124,7 @@ $Id$
* fb: video output module for the Linux framebuffer
* fb: video output module for the Linux framebuffer
* fdkaac: AAC encoder using the fdk-aac library
* fdkaac: AAC encoder using the fdk-aac library
* filesystem: Filesystem access module
* filesystem: Filesystem access module
* fingerprinter: AcoustID audio fingerprinter using chromaprint
* flac: Flac decoder using libflac
* flac: Flac decoder using libflac
* flacsys: FLAC demuxer
* flacsys: FLAC demuxer
* float_mixer: Precise float audio mixer
* float_mixer: Precise float audio mixer
...
...
modules/misc/Modules.am
View file @
0248a7fc
SOURCES_vod_rtsp = rtsp.c
SOURCES_vod_rtsp = rtsp.c
SOURCES_audioscrobbler = audioscrobbler.c
SOURCES_audioscrobbler = audioscrobbler.c
SOURCES_fingerprinter = fingerprinter.c \
fingerprinter.h \
webservices/acoustid.c \
webservices/json_fixup.h \
webservices/json.c \
webservices/json.h
SOURCES_xml = xml/libxml.c
SOURCES_xml = xml/libxml.c
libexport_plugin_la_SOURCES = \
libexport_plugin_la_SOURCES = \
...
@@ -48,6 +54,7 @@ libstats_plugin_la_LIBADD = $(AM_LIBADD)
...
@@ -48,6 +54,7 @@ libstats_plugin_la_LIBADD = $(AM_LIBADD)
libvlc_LTLIBRARIES += \
libvlc_LTLIBRARIES += \
libaudioscrobbler_plugin.la \
libaudioscrobbler_plugin.la \
libfingerprinter_plugin.la \
liblogger_plugin.la \
liblogger_plugin.la \
libstats_plugin.la
libstats_plugin.la
...
...
modules/misc/fingerprinter.c
0 → 100644
View file @
0248a7fc
/*****************************************************************************
* fingerprinter.c: Audio fingerprinter module
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_stream.h>
#include <vlc_modules.h>
#include <vlc_meta.h>
#include <vlc_url.h>
#include <vlc/vlc.h>
#include <vlc_input.h>
#include <vlc_fingerprinter.h>
#include "webservices/acoustid.h"
#include "../stream_out/chromaprint_data.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
struct
fingerprinter_sys_t
{
vlc_thread_t
thread
;
struct
{
vlc_array_t
*
queue
;
vlc_mutex_t
lock
;
}
incoming
,
processing
,
results
;
vlc_cond_t
incoming_queue_filled
;
struct
{
vlc_mutex_t
lock
;
vlc_cond_t
wait
;
int
i_input_state
;
}
condwait
;
/* tracked in sys for cancelability */
input_item_t
*
p_item
;
input_thread_t
*
p_input
;
chromaprint_fingerprint_t
chroma_fingerprint
;
char
*
psz_uri
;
/* clobberable by cleanups */
int
i_cancel_state
;
int
i
;
};
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
void
Run
(
fingerprinter_thread_t
*
);
/*****************************************************************************
* Module descriptor
****************************************************************************/
vlc_module_begin
()
set_category
(
CAT_ADVANCED
)
set_shortname
(
N_
(
"acoustid"
))
set_description
(
N_
(
"Track fingerprinter (based on Acoustid)"
))
set_capability
(
"fingerprinter"
,
1
)
set_callbacks
(
Open
,
Close
)
vlc_module_end
()
/*****************************************************************************
* Requests lifecycle
*****************************************************************************/
static
void
EnqueueRequest
(
fingerprinter_thread_t
*
f
,
fingerprint_request_t
*
r
)
{
fingerprinter_sys_t
*
p_sys
=
f
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
incoming
.
lock
);
vlc_array_append
(
p_sys
->
incoming
.
queue
,
r
);
vlc_mutex_unlock
(
&
p_sys
->
incoming
.
lock
);
vlc_cond_signal
(
&
p_sys
->
incoming_queue_filled
);
}
static
void
QueueIncomingRequests
(
fingerprinter_sys_t
*
p_sys
)
{
vlc_mutex_lock
(
&
p_sys
->
incoming
.
lock
);
int
i
=
vlc_array_count
(
p_sys
->
incoming
.
queue
);
if
(
i
==
0
)
goto
end
;
vlc_mutex_lock
(
&
p_sys
->
processing
.
lock
);
while
(
i
)
vlc_array_append
(
p_sys
->
processing
.
queue
,
vlc_array_item_at_index
(
p_sys
->
incoming
.
queue
,
--
i
)
);
vlc_array_clear
(
p_sys
->
incoming
.
queue
);
vlc_mutex_unlock
(
&
p_sys
->
processing
.
lock
);
end:
vlc_mutex_unlock
(
&
p_sys
->
incoming
.
lock
);
}
static
fingerprint_request_t
*
GetResult
(
fingerprinter_thread_t
*
f
)
{
fingerprint_request_t
*
r
=
NULL
;
fingerprinter_sys_t
*
p_sys
=
f
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
results
.
lock
);
if
(
vlc_array_count
(
p_sys
->
results
.
queue
)
)
{
r
=
vlc_array_item_at_index
(
p_sys
->
results
.
queue
,
0
);
vlc_array_remove
(
p_sys
->
results
.
queue
,
0
);
}
vlc_mutex_unlock
(
&
p_sys
->
results
.
lock
);
return
r
;
}
static
void
ApplyResult
(
fingerprint_request_t
*
p_r
,
int
i_resultid
)
{
if
(
i_resultid
>=
vlc_array_count
(
&
p_r
->
results
.
metas_array
)
)
return
;
vlc_meta_t
*
p_meta
=
(
vlc_meta_t
*
)
vlc_array_item_at_index
(
&
p_r
->
results
.
metas_array
,
i_resultid
);
input_item_t
*
p_item
=
p_r
->
p_item
;
vlc_mutex_lock
(
&
p_item
->
lock
);
vlc_meta_Merge
(
p_item
->
p_meta
,
p_meta
);
vlc_mutex_unlock
(
&
p_item
->
lock
);
}
static
void
cancelDoFingerprint
(
void
*
p_arg
)
{
fingerprinter_sys_t
*
p_sys
=
(
fingerprinter_sys_t
*
)
p_arg
;
if
(
p_sys
->
p_input
)
{
input_Stop
(
p_sys
->
p_input
,
true
);
input_Close
(
p_sys
->
p_input
);
}
/* cleanup temporary result */
if
(
p_sys
->
chroma_fingerprint
.
psz_fingerprint
)
FREENULL
(
p_sys
->
chroma_fingerprint
.
psz_fingerprint
);
if
(
p_sys
->
p_item
)
input_item_Release
(
p_sys
->
p_item
);
}
static
int
inputStateCallback
(
vlc_object_t
*
obj
,
const
char
*
var
,
vlc_value_t
old
,
vlc_value_t
cur
,
void
*
p_data
)
{
VLC_UNUSED
(
obj
);
VLC_UNUSED
(
var
);
VLC_UNUSED
(
old
);
fingerprinter_sys_t
*
p_sys
=
(
fingerprinter_sys_t
*
)
p_data
;
if
(
cur
.
i_int
!=
INPUT_EVENT_STATE
)
return
VLC_SUCCESS
;
p_sys
->
condwait
.
i_input_state
=
var_GetInteger
(
p_sys
->
p_input
,
"state"
);
vlc_cond_signal
(
&
p_sys
->
condwait
.
wait
);
return
VLC_SUCCESS
;
}
static
void
DoFingerprint
(
vlc_object_t
*
p_this
,
fingerprinter_sys_t
*
p_sys
,
acoustid_fingerprint_t
*
fp
)
{
p_sys
->
p_input
=
NULL
;
p_sys
->
p_item
=
NULL
;
p_sys
->
chroma_fingerprint
.
psz_fingerprint
=
NULL
;
vlc_cleanup_push
(
cancelDoFingerprint
,
p_sys
);
p_sys
->
p_item
=
input_item_New
(
NULL
,
NULL
);
if
(
!
p_sys
->
p_item
)
goto
end
;
char
*
psz_sout_option
;
/* Note: need at -max- 2 channels, but we can't guess it before playing */
/* the stereo upmix could make the mono tracks fingerprint to differ :/ */
if
(
asprintf
(
&
psz_sout_option
,
"sout=#transcode{acodec=%s,channels=2}:chromaprint"
,
(
VLC_CODEC_S16L
==
VLC_CODEC_S16N
)
?
"s16l"
:
"s16b"
)
==
-
1
)
goto
end
;
input_item_AddOption
(
p_sys
->
p_item
,
psz_sout_option
,
VLC_INPUT_OPTION_TRUSTED
);
free
(
psz_sout_option
);
input_item_AddOption
(
p_sys
->
p_item
,
"vout=dummy"
,
VLC_INPUT_OPTION_TRUSTED
);
input_item_AddOption
(
p_sys
->
p_item
,
"aout=dummy"
,
VLC_INPUT_OPTION_TRUSTED
);
if
(
fp
->
i_duration
)
{
if
(
asprintf
(
&
psz_sout_option
,
"stop-time=%u"
,
fp
->
i_duration
)
==
-
1
)
goto
end
;
input_item_AddOption
(
p_sys
->
p_item
,
psz_sout_option
,
VLC_INPUT_OPTION_TRUSTED
);
free
(
psz_sout_option
);
}
input_item_SetURI
(
p_sys
->
p_item
,
p_sys
->
psz_uri
)
;
p_sys
->
p_input
=
input_Create
(
p_this
,
p_sys
->
p_item
,
"fingerprinter"
,
NULL
);
if
(
p_sys
->
p_input
)
{
p_sys
->
chroma_fingerprint
.
i_duration
=
fp
->
i_duration
;
var_Create
(
p_sys
->
p_input
,
"fingerprint-data"
,
VLC_VAR_ADDRESS
);
var_SetAddress
(
p_sys
->
p_input
,
"fingerprint-data"
,
&
p_sys
->
chroma_fingerprint
);
input_Start
(
p_sys
->
p_input
);
/* Wait for input to start && end */
p_sys
->
condwait
.
i_input_state
=
var_GetInteger
(
p_sys
->
p_input
,
"state"
);
if
(
likely
(
var_AddCallback
(
p_sys
->
p_input
,
"intf-event"
,
inputStateCallback
,
p_sys
)
==
VLC_SUCCESS
)
)
{
while
(
p_sys
->
condwait
.
i_input_state
<=
PAUSE_S
)
{
vlc_mutex_lock
(
&
p_sys
->
condwait
.
lock
);
mutex_cleanup_push
(
&
p_sys
->
condwait
.
lock
);
vlc_cond_wait
(
&
p_sys
->
condwait
.
wait
,
&
p_sys
->
condwait
.
lock
);
vlc_cleanup_run
();
}
var_DelCallback
(
p_sys
->
p_input
,
"intf-event"
,
inputStateCallback
,
p_sys
);
}
input_Stop
(
p_sys
->
p_input
,
true
);
input_Close
(
p_sys
->
p_input
);
p_sys
->
p_input
=
NULL
;
if
(
p_sys
->
chroma_fingerprint
.
psz_fingerprint
)
{
fp
->
psz_fingerprint
=
strdup
(
p_sys
->
chroma_fingerprint
.
psz_fingerprint
);
if
(
!
fp
->
i_duration
)
/* had not given hint */
fp
->
i_duration
=
p_sys
->
chroma_fingerprint
.
i_duration
;
}
}
end:
vlc_cleanup_run
(
);
}
/*****************************************************************************
* Open:
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
{
fingerprinter_thread_t
*
p_fingerprinter
=
(
fingerprinter_thread_t
*
)
p_this
;
fingerprinter_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
fingerprinter_sys_t
));
if
(
!
p_sys
)
return
VLC_ENOMEM
;
p_fingerprinter
->
p_sys
=
p_sys
;
p_sys
->
incoming
.
queue
=
vlc_array_new
();
vlc_mutex_init
(
&
p_sys
->
incoming
.
lock
);
vlc_cond_init
(
&
p_sys
->
incoming_queue_filled
);
p_sys
->
processing
.
queue
=
vlc_array_new
();
vlc_mutex_init
(
&
p_sys
->
processing
.
lock
);
p_sys
->
results
.
queue
=
vlc_array_new
();
vlc_mutex_init
(
&
p_sys
->
results
.
lock
);
vlc_mutex_init
(
&
p_sys
->
condwait
.
lock
);
vlc_cond_init
(
&
p_sys
->
condwait
.
wait
);
p_sys
->
psz_uri
=
NULL
;
p_fingerprinter
->
pf_run
=
Run
;
p_fingerprinter
->
pf_enqueue
=
EnqueueRequest
;
p_fingerprinter
->
pf_getresults
=
GetResult
;
p_fingerprinter
->
pf_apply
=
ApplyResult
;
var_Create
(
p_fingerprinter
,
"results-available"
,
VLC_VAR_BOOL
);
if
(
p_fingerprinter
->
pf_run
&&
vlc_clone
(
&
p_sys
->
thread
,
(
void
*
(
*
)
(
void
*
))
p_fingerprinter
->
pf_run
,
p_fingerprinter
,
VLC_THREAD_PRIORITY_LOW
)
)
{
msg_Err
(
p_fingerprinter
,
"cannot spawn fingerprinter thread"
);
goto
error
;
}
return
VLC_SUCCESS
;
error:
free
(
p_sys
);
return
VLC_EGENERIC
;
}
/*****************************************************************************
* Close:
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
fingerprinter_thread_t
*
p_fingerprinter
=
(
fingerprinter_thread_t
*
)
p_this
;
fingerprinter_sys_t
*
p_sys
=
p_fingerprinter
->
p_sys
;
vlc_cancel
(
p_sys
->
thread
);
vlc_join
(
p_sys
->
thread
,
NULL
);
vlc_mutex_destroy
(
&
p_sys
->
condwait
.
lock
);
vlc_cond_destroy
(
&
p_sys
->
condwait
.
wait
);
for
(
int
i
=
0
;
i
<
vlc_array_count
(
p_sys
->
incoming
.
queue
);
i
++
)
fingerprint_request_Delete
(
vlc_array_item_at_index
(
p_sys
->
incoming
.
queue
,
i
)
);
vlc_array_destroy
(
p_sys
->
incoming
.
queue
);
vlc_mutex_destroy
(
&
p_sys
->
incoming
.
lock
);
vlc_cond_destroy
(
&
p_sys
->
incoming_queue_filled
);
for
(
int
i
=
0
;
i
<
vlc_array_count
(
p_sys
->
processing
.
queue
);
i
++
)
fingerprint_request_Delete
(
vlc_array_item_at_index
(
p_sys
->
processing
.
queue
,
i
)
);
vlc_array_destroy
(
p_sys
->
processing
.
queue
);
vlc_mutex_destroy
(
&
p_sys
->
processing
.
lock
);
for
(
int
i
=
0
;
i
<
vlc_array_count
(
p_sys
->
results
.
queue
);
i
++
)
fingerprint_request_Delete
(
vlc_array_item_at_index
(
p_sys
->
results
.
queue
,
i
)
);
vlc_array_destroy
(
p_sys
->
results
.
queue
);
vlc_mutex_destroy
(
&
p_sys
->
results
.
lock
);
free
(
p_sys
);
}
static
void
fill_metas_with_results
(
fingerprint_request_t
*
p_r
,
acoustid_fingerprint_t
*
p_f
)
{
for
(
unsigned
int
i
=
0
;
i
<
p_f
->
results
.
count
;
i
++
)
{
acoustid_result_t
*
p_result
=
&
p_f
->
results
.
p_results
[
i
];
for
(
unsigned
int
j
=
0
;
j
<
p_result
->
recordings
.
count
;
j
++
)
{
musicbrainz_recording_t
*
p_record
=
&
p_result
->
recordings
.
p_recordings
[
j
];
vlc_meta_t
*
p_meta
=
vlc_meta_New
();
if
(
p_meta
)
{
vlc_meta_Set
(
p_meta
,
vlc_meta_Title
,
p_record
->
psz_title
);
vlc_meta_Set
(
p_meta
,
vlc_meta_Artist
,
p_record
->
psz_artist
);
vlc_meta_AddExtra
(
p_meta
,
"musicbrainz-id"
,
p_record
->
sz_musicbrainz_id
);
vlc_array_append
(
&
p_r
->
results
.
metas_array
,
p_meta
);
}
}
}
}
/*****************************************************************************
* Run :
*****************************************************************************/
static
void
cancelRun
(
void
*
p_arg
)
{
fingerprinter_sys_t
*
p_sys
=
(
fingerprinter_sys_t
*
)
p_arg
;
if
(
vlc_array_count
(
p_sys
->
processing
.
queue
)
)
vlc_array_clear
(
p_sys
->
processing
.
queue
);
if
(
p_sys
->
psz_uri
)
free
(
p_sys
->
psz_uri
);
}
static
void
clearPrint
(
void
*
p_arg
)
{
acoustid_fingerprint_t
*
acoustid_print
=
(
acoustid_fingerprint_t
*
)
p_arg
;
for
(
unsigned
int
j
=
0
;
j
<
acoustid_print
->
results
.
count
;
j
++
)
free_acoustid_result_t
(
&
acoustid_print
->
results
.
p_results
[
j
]
);
if
(
acoustid_print
->
results
.
count
)
free
(
acoustid_print
->
results
.
p_results
);
if
(
acoustid_print
->
psz_fingerprint
)
free
(
acoustid_print
->
psz_fingerprint
);
}
static
void
Run
(
fingerprinter_thread_t
*
p_fingerprinter
)
{
fingerprinter_sys_t
*
p_sys
=
p_fingerprinter
->
p_sys
;
/* main loop */
for
(;;)
{
vlc_mutex_lock
(
&
p_sys
->
processing
.
lock
);
mutex_cleanup_push
(
&
p_sys
->
processing
.
lock
);
vlc_cond_timedwait
(
&
p_sys
->
incoming_queue_filled
,
&
p_sys
->
processing
.
lock
,
mdate
()
+
1000000
);
vlc_cleanup_run
();
QueueIncomingRequests
(
p_sys
);
vlc_mutex_lock
(
&
p_sys
->
processing
.
lock
);
// L0
mutex_cleanup_push
(
&
p_sys
->
processing
.
lock
);
vlc_cleanup_push
(
cancelRun
,
p_sys
);
// C1
//**
for
(
p_sys
->
i
=
0
;
p_sys
->
i
<
vlc_array_count
(
p_sys
->
processing
.
queue
);
p_sys
->
i
++
)
{
fingerprint_request_t
*
p_data
=
vlc_array_item_at_index
(
p_sys
->
processing
.
queue
,
p_sys
->
i
);
acoustid_fingerprint_t
acoustid_print
;
memset
(
&
acoustid_print
,
0
,
sizeof
(
acoustid_fingerprint_t
)
);
vlc_cleanup_push
(
clearPrint
,
&
acoustid_print
);
// C2
p_sys
->
psz_uri
=
input_item_GetURI
(
p_data
->
p_item
);
if
(
p_sys
->
psz_uri
)
{
/* overwrite with hint, as in this case, fingerprint's session will be truncated */
if
(
p_data
->
i_duration
)
acoustid_print
.
i_duration
=
p_data
->
i_duration
;
DoFingerprint
(
VLC_OBJECT
(
p_fingerprinter
),
p_sys
,
&
acoustid_print
);
DoAcoustIdWebRequest
(
VLC_OBJECT
(
p_fingerprinter
),
&
acoustid_print
);
fill_metas_with_results
(
p_data
,
&
acoustid_print
);
FREENULL
(
p_sys
->
psz_uri
);
}
vlc_cleanup_run
(
);
// C2
/* copy results */
vlc_mutex_lock
(
&
p_sys
->
results
.
lock
);
vlc_array_append
(
p_sys
->
results
.
queue
,
p_data
);
vlc_mutex_unlock
(
&
p_sys
->
results
.
lock
);
vlc_testcancel
();
}
if
(
vlc_array_count
(
p_sys
->
processing
.
queue
)
)
{
var_TriggerCallback
(
p_fingerprinter
,
"results-available"
);
vlc_array_clear
(
p_sys
->
processing
.
queue
);
}
vlc_cleanup_pop
(
);
// C1
//**
vlc_cleanup_run
();
// L0
}
}
modules/misc/webservices/acoustid.c
0 → 100644
View file @
0248a7fc
/*****************************************************************************
* acoustid.c: AcoustId webservice parser
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_stream.h>
#include <limits.h>
#include <vlc_memory.h>
#include <vlc/vlc.h>
#include "acoustid.h"
#include "use_json.h"
/*****************************************************************************
* Requests lifecycle
*****************************************************************************/
void
free_acoustid_result_t
(
acoustid_result_t
*
r
)
{
free
(
r
->
psz_id
);
for
(
unsigned
int
i
=
0
;
i
<
r
->
recordings
.
count
;
i
++
)
{
free
(
r
->
recordings
.
p_recordings
[
i
].
psz_artist
);
free
(
r
->
recordings
.
p_recordings
[
i
].
psz_title
);
}
free
(
r
->
recordings
.
p_recordings
);
}
static
json_value
*
jsongetbyname
(
json_value
*
object
,
const
char
*
psz_name
)
{
if
(
object
->
type
!=
json_object
)
return
NULL
;
for
(
unsigned
int
i
=
0
;
i
<
object
->
u
.
object
.
length
;
i
++
)
if
(
strcmp
(
object
->
u
.
object
.
values
[
i
].
name
,
psz_name
)
==
0
)
return
object
->
u
.
object
.
values
[
i
].
value
;
return
NULL
;
}
static
void
parse_artists
(
json_value
*
node
,
musicbrainz_recording_t
*
record
)
{
/* take only main */
if
(
!
node
||
node
->
type
!=
json_array
||
node
->
u
.
array
.
length
<
1
)
return
;
json_value
*
artistnode
=
node
->
u
.
array
.
values
[
0
];
json_value
*
value
=
jsongetbyname
(
artistnode
,
"name"
);
if
(
value
&&
value
->
type
==
json_string
)
record
->
psz_artist
=
strdup
(
value
->
u
.
string
.
ptr
);
}
static
void
parse_recordings
(
vlc_object_t
*
p_obj
,
json_value
*
node
,
acoustid_result_t
*
p_result
)
{
if
(
!
node
||
node
->
type
!=
json_array
)
return
;
p_result
->
recordings
.
p_recordings
=
calloc
(
node
->
u
.
array
.
length
,
sizeof
(
musicbrainz_recording_t
)
);
if
(
!
p_result
->
recordings
.
p_recordings
)
return
;
p_result
->
recordings
.
count
=
node
->
u
.
array
.
length
;
for
(
unsigned
int
i
=
0
;
i
<
node
->
u
.
array
.
length
;
i
++
)
{
musicbrainz_recording_t
*
record
=
&
p_result
->
recordings
.
p_recordings
[
i
];
json_value
*
recordnode
=
node
->
u
.
array
.
values
[
i
];
if
(
!
recordnode
||
recordnode
->
type
!=
json_object
)
break
;
json_value
*
value
=
jsongetbyname
(
recordnode
,
"title"
);
if
(
value
&&
value
->
type
==
json_string
)
record
->
psz_title
=
strdup
(
value
->
u
.
string
.
ptr
);
value
=
jsongetbyname
(
recordnode
,
"id"
);
if
(
value
&&
value
->
type
==
json_string
)
strncpy
(
record
->
sz_musicbrainz_id
,
value
->
u
.
string
.
ptr
,
MB_ID_SIZE
);
parse_artists
(
jsongetbyname
(
recordnode
,
"artists"
),
record
);
msg_Dbg
(
p_obj
,
"recording %d title %s %36s %s"
,
i
,
record
->
psz_title
,
record
->
sz_musicbrainz_id
,
record
->
psz_artist
);
}
}
static
bool
ParseJson
(
vlc_object_t
*
p_obj
,
char
*
psz_buffer
,
acoustid_results_t
*
p_results
)
{
json_settings
settings
;
char
psz_error
[
128
];
memset
(
&
settings
,
0
,
sizeof
(
json_settings
));
json_value
*
root
=
json_parse_ex
(
&
settings
,
psz_buffer
,
psz_error
);
if
(
root
==
NULL
)
{
msg_Warn
(
p_obj
,
"Can't parse json data: %s"
,
psz_error
);
goto
error
;
}
if
(
root
->
type
!=
json_object
)
{
msg_Warn
(
p_obj
,
"wrong json root node"
);
goto
error
;
}
json_value
*
node
=
jsongetbyname
(
root
,
"status"
);
if
(
!
node
||
node
->
type
!=
json_string
)
{
msg_Warn
(
p_obj
,
"status node not found or invalid"
);
goto
error
;
}
if
(
strcmp
(
node
->
u
.
string
.
ptr
,
"ok"
)
!=
0
)
{
msg_Warn
(
p_obj
,
"Bad request status"
);
goto
error
;
}
node
=
jsongetbyname
(
root
,
"results"
);
if
(
!
node
||
node
->
type
!=
json_array
)
{
msg_Warn
(
p_obj
,
"Bad results array or no results"
);
goto
error
;
}
p_results
->
p_results
=
calloc
(
node
->
u
.
array
.
length
,
sizeof
(
acoustid_result_t
)
);
if
(
!
p_results
->
p_results
)
goto
error
;
p_results
->
count
=
node
->
u
.
array
.
length
;
for
(
unsigned
int
i
=
0
;
i
<
node
->
u
.
array
.
length
;
i
++
)
{
json_value
*
resultnode
=
node
->
u
.
array
.
values
[
i
];
if
(
resultnode
&&
resultnode
->
type
==
json_object
)
{
acoustid_result_t
*
p_result
=
&
p_results
->
p_results
[
i
];
json_value
*
value
=
jsongetbyname
(
resultnode
,
"score"
);
if
(
value
&&
value
->
type
==
json_double
)
p_result
->
d_score
=
value
->
u
.
dbl
;
value
=
jsongetbyname
(
resultnode
,
"id"
);
if
(
value
&&
value
->
type
==
json_string
)
p_result
->
psz_id
=
strdup
(
value
->
u
.
string
.
ptr
);
parse_recordings
(
p_obj
,
jsongetbyname
(
resultnode
,
"recordings"
),
p_result
);
}
}
json_value_free
(
root
);
return
true
;
error:
if
(
root
)
json_value_free
(
root
);
return
false
;
}
struct
webrequest_t
{
stream_t
*
p_stream
;
char
*
psz_url
;
char
*
p_buffer
;
};
static
void
cancelDoAcoustIdWebRequest
(
void
*
p_arg
)
{
struct
webrequest_t
*
p_request
=
(
struct
webrequest_t
*
)
p_arg
;
if
(
p_request
->
p_stream
)
stream_Delete
(
p_request
->
p_stream
);
if
(
p_request
->
psz_url
)
free
(
p_request
->
psz_url
);
if
(
p_request
->
p_buffer
)
free
(
p_request
->
p_buffer
);
}
int
DoAcoustIdWebRequest
(
vlc_object_t
*
p_obj
,
acoustid_fingerprint_t
*
p_data
)
{
int
i_ret
;
int
i_status
;
struct
webrequest_t
request
=
{
NULL
,
NULL
,
NULL
};
if
(
!
p_data
->
psz_fingerprint
)
return
VLC_SUCCESS
;
i_ret
=
asprintf
(
&
request
.
psz_url
,
"http://fingerprint.videolan.org/acoustid.php?meta=recordings+tracks+usermeta+releases&duration=%d&fingerprint=%s"
,
p_data
->
i_duration
,
p_data
->
psz_fingerprint
);
if
(
i_ret
<
1
)
return
VLC_EGENERIC
;
vlc_cleanup_push
(
cancelDoAcoustIdWebRequest
,
&
request
);
msg_Dbg
(
p_obj
,
"Querying AcoustID from %s"
,
request
.
psz_url
);
request
.
p_stream
=
stream_UrlNew
(
p_obj
,
request
.
psz_url
);
if
(
!
request
.
p_stream
)
{
i_status
=
VLC_EGENERIC
;
goto
cleanup
;
}
/* read answer */
i_ret
=
0
;
for
(
;;
)
{
int
i_read
=
65536
;
if
(
i_ret
>=
INT_MAX
-
i_read
)
break
;
request
.
p_buffer
=
realloc_or_free
(
request
.
p_buffer
,
1
+
i_ret
+
i_read
);
if
(
!
request
.
p_buffer
)
{
i_status
=
VLC_ENOMEM
;
goto
cleanup
;
}
i_read
=
stream_Read
(
request
.
p_stream
,
&
request
.
p_buffer
[
i_ret
],
i_read
);
if
(
i_read
<=
0
)
break
;
i_ret
+=
i_read
;
}
stream_Delete
(
request
.
p_stream
);
request
.
p_stream
=
NULL
;
request
.
p_buffer
[
i_ret
]
=
0
;
int
i_canc
=
vlc_savecancel
();
if
(
ParseJson
(
p_obj
,
request
.
p_buffer
,
&
p_data
->
results
)
)
{
msg_Dbg
(
p_obj
,
"results count == %d"
,
p_data
->
results
.
count
);
}
else
{
msg_Dbg
(
p_obj
,
"No results"
);
}
vlc_restorecancel
(
i_canc
);
i_status
=
VLC_SUCCESS
;
cleanup:
vlc_cleanup_run
(
);
return
i_status
;
}
modules/misc/webservices/acoustid.h
0 → 100644
View file @
0248a7fc
/*****************************************************************************
* acoustid.h: AcoustId webservice parser
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#define MB_ID_SIZE 36
struct
musicbrainz_recording_t
{
char
*
psz_artist
;
char
*
psz_title
;
char
sz_musicbrainz_id
[
MB_ID_SIZE
];
};
typedef
struct
musicbrainz_recording_t
musicbrainz_recording_t
;
struct
acoustid_result_t
{
double
d_score
;
char
*
psz_id
;
struct
{
unsigned
int
count
;
musicbrainz_recording_t
*
p_recordings
;
}
recordings
;
};
typedef
struct
acoustid_result_t
acoustid_result_t
;
struct
acoustid_results_t
{
acoustid_result_t
*
p_results
;
unsigned
int
count
;
};
typedef
struct
acoustid_results_t
acoustid_results_t
;
struct
acoustid_fingerprint_t
{
char
*
psz_fingerprint
;
unsigned
int
i_duration
;
acoustid_results_t
results
;
};
typedef
struct
acoustid_fingerprint_t
acoustid_fingerprint_t
;
int
DoAcoustIdWebRequest
(
vlc_object_t
*
p_obj
,
acoustid_fingerprint_t
*
p_data
);
void
free_acoustid_result_t
(
acoustid_result_t
*
r
);
modules/misc/webservices/json.c
0 → 100644
View file @
0248a7fc
/* vim: set et ts=3 sw=3 ft=c:
*
* Copyright (C) 2012 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include "json.h"
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#endif
#ifdef __cplusplus
const
struct
_json_value
json_value_none
;
/* zero-d by ctor */
#else
const
struct
_json_value
json_value_none
=
{
0
};
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef
unsigned
short
json_uchar
;
static
unsigned
char
hex_value
(
json_char
c
)
{
if
(
c
>=
'A'
&&
c
<=
'F'
)
return
(
c
-
'A'
)
+
10
;
if
(
c
>=
'a'
&&
c
<=
'f'
)
return
(
c
-
'a'
)
+
10
;
if
(
c
>=
'0'
&&
c
<=
'9'
)
return
c
-
'0'
;
return
0xFF
;
}
typedef
struct
{
json_settings
settings
;
int
first_pass
;
unsigned
long
used_memory
;
unsigned
int
uint_max
;
unsigned
long
ulong_max
;
}
json_state
;
static
void
*
json_alloc
(
json_state
*
state
,
unsigned
long
size
,
int
zero
)
{
void
*
mem
;
if
((
state
->
ulong_max
-
state
->
used_memory
)
<
size
)
return
0
;
if
(
state
->
settings
.
max_memory
&&
(
state
->
used_memory
+=
size
)
>
state
->
settings
.
max_memory
)
{
return
0
;
}
if
(
!
(
mem
=
zero
?
calloc
(
size
,
1
)
:
malloc
(
size
)))
return
0
;
return
mem
;
}
static
int
new_value
(
json_state
*
state
,
json_value
**
top
,
json_value
**
root
,
json_value
**
alloc
,
json_type
type
)
{
json_value
*
value
;
int
values_size
;
if
(
!
state
->
first_pass
)
{
value
=
*
top
=
*
alloc
;
*
alloc
=
(
*
alloc
)
->
_reserved
.
next_alloc
;
if
(
!*
root
)
*
root
=
value
;
switch
(
value
->
type
)
{
case
json_array
:
if
(
!
(
value
->
u
.
array
.
values
=
(
json_value
**
)
json_alloc
(
state
,
value
->
u
.
array
.
length
*
sizeof
(
json_value
*
),
0
))
)
{
return
0
;
}
break
;
case
json_object
:
values_size
=
sizeof
(
*
value
->
u
.
object
.
values
)
*
value
->
u
.
object
.
length
;
if
(
!
((
*
(
void
**
)
&
value
->
u
.
object
.
values
)
=
json_alloc
(
state
,
values_size
+
((
unsigned
long
)
value
->
u
.
object
.
values
),
0
))
)
{
return
0
;
}
value
->
_reserved
.
object_mem
=
(
*
(
char
**
)
&
value
->
u
.
object
.
values
)
+
values_size
;
break
;
case
json_string
:
if
(
!
(
value
->
u
.
string
.
ptr
=
(
json_char
*
)
json_alloc
(
state
,
(
value
->
u
.
string
.
length
+
1
)
*
sizeof
(
json_char
),
0
))
)
{
return
0
;
}
break
;
default:
break
;
};
value
->
u
.
array
.
length
=
0
;
return
1
;
}
value
=
(
json_value
*
)
json_alloc
(
state
,
sizeof
(
json_value
),
1
);
if
(
!
value
)
return
0
;
if
(
!*
root
)
*
root
=
value
;
value
->
type
=
type
;
value
->
parent
=
*
top
;
if
(
*
alloc
)
(
*
alloc
)
->
_reserved
.
next_alloc
=
value
;
*
alloc
=
*
top
=
value
;
return
1
;
}
#define e_off \
((int) (i - cur_line_begin))
#define whitespace \
case '\n': ++ cur_line; cur_line_begin = i; \
case ' ': case '\t': case '\r'
#define string_add(b) \
do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
const
static
int
flag_next
=
1
,
flag_reproc
=
2
,
flag_need_comma
=
4
,
flag_seek_value
=
8
,
flag_exponent
=
16
,
flag_got_exponent_sign
=
32
,
flag_escaped
=
64
,
flag_string
=
128
,
flag_need_colon
=
256
,
flag_done
=
512
;
json_value
*
json_parse_ex
(
json_settings
*
settings
,
const
json_char
*
json
,
char
*
error_buf
)
{
json_char
error
[
128
];
unsigned
int
cur_line
;
const
json_char
*
cur_line_begin
,
*
i
;
json_value
*
top
,
*
root
,
*
alloc
=
0
;
json_state
state
;
int
flags
;
error
[
0
]
=
'\0'
;
memset
(
&
state
,
0
,
sizeof
(
json_state
));
memcpy
(
&
state
.
settings
,
settings
,
sizeof
(
json_settings
));
memset
(
&
state
.
uint_max
,
0xFF
,
sizeof
(
state
.
uint_max
));
memset
(
&
state
.
ulong_max
,
0xFF
,
sizeof
(
state
.
ulong_max
));
state
.
uint_max
-=
8
;
/* limit of how much can be added before next check */
state
.
ulong_max
-=
8
;
for
(
state
.
first_pass
=
1
;
state
.
first_pass
>=
0
;
--
state
.
first_pass
)
{
json_uchar
uchar
;
unsigned
char
uc_b1
,
uc_b2
,
uc_b3
,
uc_b4
;
json_char
*
string
;
unsigned
int
string_length
;
top
=
root
=
0
;
flags
=
flag_seek_value
;
cur_line
=
1
;
cur_line_begin
=
json
;
for
(
i
=
json
;;
++
i
)
{
json_char
b
=
*
i
;
if
(
flags
&
flag_done
)
{
if
(
!
b
)
break
;
switch
(
b
)
{
whitespace:
continue
;
default:
sprintf
(
error
,
"%d:%d: Trailing garbage: `%c`"
,
cur_line
,
e_off
,
b
);
goto
e_failed
;
};
}
if
(
flags
&
flag_string
)
{
if
(
!
b
)
{
sprintf
(
error
,
"Unexpected EOF in string (at %d:%d)"
,
cur_line
,
e_off
);
goto
e_failed
;
}
if
(
string_length
>
state
.
uint_max
)
goto
e_overflow
;
if
(
flags
&
flag_escaped
)
{
flags
&=
~
flag_escaped
;
switch
(
b
)
{
case
'b'
:
string_add
(
'\b'
);
break
;
case
'f'
:
string_add
(
'\f'
);
break
;
case
'n'
:
string_add
(
'\n'
);
break
;
case
'r'
:
string_add
(
'\r'
);
break
;
case
't'
:
string_add
(
'\t'
);
break
;
case
'u'
:
if
((
uc_b1
=
hex_value
(
*++
i
))
==
0xFF
||
(
uc_b2
=
hex_value
(
*++
i
))
==
0xFF
||
(
uc_b3
=
hex_value
(
*++
i
))
==
0xFF
||
(
uc_b4
=
hex_value
(
*++
i
))
==
0xFF
)
{
sprintf
(
error
,
"Invalid character value `%c` (at %d:%d)"
,
b
,
cur_line
,
e_off
);
goto
e_failed
;
}
uc_b1
=
uc_b1
*
16
+
uc_b2
;
uc_b2
=
uc_b3
*
16
+
uc_b4
;
uchar
=
((
json_char
)
uc_b1
)
*
256
+
uc_b2
;
if
(
sizeof
(
json_char
)
>=
sizeof
(
json_uchar
)
||
(
uc_b1
==
0
&&
uc_b2
<=
0x7F
))
{
string_add
((
json_char
)
uchar
);
break
;
}
if
(
uchar
<=
0x7FF
)
{
if
(
state
.
first_pass
)
string_length
+=
2
;
else
{
string
[
string_length
++
]
=
0xC0
|
((
uc_b2
&
0xC0
)
>>
6
)
|
((
uc_b1
&
0x3
)
<<
3
);
string
[
string_length
++
]
=
0x80
|
(
uc_b2
&
0x3F
);
}
break
;
}
if
(
state
.
first_pass
)
string_length
+=
3
;
else
{
string
[
string_length
++
]
=
0xE0
|
((
uc_b1
&
0xF0
)
>>
4
);
string
[
string_length
++
]
=
0x80
|
((
uc_b1
&
0xF
)
<<
2
)
|
((
uc_b2
&
0xC0
)
>>
6
);
string
[
string_length
++
]
=
0x80
|
(
uc_b2
&
0x3F
);
}
break
;
default:
string_add
(
b
);
};
continue
;
}
if
(
b
==
'\\'
)
{
flags
|=
flag_escaped
;
continue
;
}
if
(
b
==
'"'
)
{
if
(
!
state
.
first_pass
)
string
[
string_length
]
=
0
;
flags
&=
~
flag_string
;
string
=
0
;
switch
(
top
->
type
)
{
case
json_string
:
top
->
u
.
string
.
length
=
string_length
;
flags
|=
flag_next
;
break
;
case
json_object
:
if
(
state
.
first_pass
)
(
*
(
json_char
**
)
&
top
->
u
.
object
.
values
)
+=
string_length
+
1
;
else
{
top
->
u
.
object
.
values
[
top
->
u
.
object
.
length
].
name
=
(
json_char
*
)
top
->
_reserved
.
object_mem
;
(
*
(
json_char
**
)
&
top
->
_reserved
.
object_mem
)
+=
string_length
+
1
;
}
flags
|=
flag_seek_value
|
flag_need_colon
;
continue
;
default:
break
;
};
}
else
{
string_add
(
b
);
continue
;
}
}
if
(
flags
&
flag_seek_value
)
{
switch
(
b
)
{
whitespace:
continue
;
case
']'
:
if
(
top
->
type
==
json_array
)
flags
=
(
flags
&
~
(
flag_need_comma
|
flag_seek_value
))
|
flag_next
;
else
if
(
!
state
.
settings
.
settings
&
json_relaxed_commas
)
{
sprintf
(
error
,
"%d:%d: Unexpected ]"
,
cur_line
,
e_off
);
goto
e_failed
;
}
break
;
default:
if
(
flags
&
flag_need_comma
)
{
if
(
b
==
','
)
{
flags
&=
~
flag_need_comma
;
continue
;
}
else
{
sprintf
(
error
,
"%d:%d: Expected , before %c"
,
cur_line
,
e_off
,
b
);
goto
e_failed
;
}
}
if
(
flags
&
flag_need_colon
)
{
if
(
b
==
':'
)
{
flags
&=
~
flag_need_colon
;
continue
;
}
else
{
sprintf
(
error
,
"%d:%d: Expected : before %c"
,
cur_line
,
e_off
,
b
);
goto
e_failed
;
}
}
flags
&=
~
flag_seek_value
;
switch
(
b
)
{
case
'{'
:
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_object
))
goto
e_alloc_failure
;
continue
;
case
'['
:
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_array
))
goto
e_alloc_failure
;
flags
|=
flag_seek_value
;
continue
;
case
'"'
:
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_string
))
goto
e_alloc_failure
;
flags
|=
flag_string
;
string
=
top
->
u
.
string
.
ptr
;
string_length
=
0
;
continue
;
case
't'
:
if
(
*
(
++
i
)
!=
'r'
||
*
(
++
i
)
!=
'u'
||
*
(
++
i
)
!=
'e'
)
goto
e_unknown_value
;
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_boolean
))
goto
e_alloc_failure
;
top
->
u
.
boolean
=
1
;
flags
|=
flag_next
;
break
;
case
'f'
:
if
(
*
(
++
i
)
!=
'a'
||
*
(
++
i
)
!=
'l'
||
*
(
++
i
)
!=
's'
||
*
(
++
i
)
!=
'e'
)
goto
e_unknown_value
;
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_boolean
))
goto
e_alloc_failure
;
flags
|=
flag_next
;
break
;
case
'n'
:
if
(
*
(
++
i
)
!=
'u'
||
*
(
++
i
)
!=
'l'
||
*
(
++
i
)
!=
'l'
)
goto
e_unknown_value
;
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_null
))
goto
e_alloc_failure
;
flags
|=
flag_next
;
break
;
default:
if
(
isdigit
(
b
)
||
b
==
'-'
)
{
if
(
!
new_value
(
&
state
,
&
top
,
&
root
,
&
alloc
,
json_integer
))
goto
e_alloc_failure
;
flags
&=
~
(
flag_exponent
|
flag_got_exponent_sign
);
if
(
state
.
first_pass
)
continue
;
if
(
top
->
type
==
json_double
)
top
->
u
.
dbl
=
strtod
(
i
,
(
json_char
**
)
&
i
);
else
top
->
u
.
integer
=
strtol
(
i
,
(
json_char
**
)
&
i
,
10
);
flags
|=
flag_next
|
flag_reproc
;
}
else
{
sprintf
(
error
,
"%d:%d: Unexpected %c when seeking value"
,
cur_line
,
e_off
,
b
);
goto
e_failed
;
}
};
};
}
else
{
switch
(
top
->
type
)
{
case
json_object
:
switch
(
b
)
{
whitespace:
continue
;
case
'"'
:
if
(
flags
&
flag_need_comma
&&
(
!
state
.
settings
.
settings
&
json_relaxed_commas
))
{
sprintf
(
error
,
"%d:%d: Expected , before
\"
"
,
cur_line
,
e_off
);
goto
e_failed
;
}
flags
|=
flag_string
;
string
=
(
json_char
*
)
top
->
_reserved
.
object_mem
;
string_length
=
0
;
break
;
case
'}'
:
flags
=
(
flags
&
~
flag_need_comma
)
|
flag_next
;
break
;
case
','
:
if
(
flags
&
flag_need_comma
)
{
flags
&=
~
flag_need_comma
;
break
;
}
default:
sprintf
(
error
,
"%d:%d: Unexpected `%c` in object"
,
cur_line
,
e_off
,
b
);
goto
e_failed
;
};
break
;
case
json_integer
:
case
json_double
:
if
(
isdigit
(
b
))
continue
;
if
(
b
==
'e'
||
b
==
'E'
)
{
if
(
!
(
flags
&
flag_exponent
))
{
flags
|=
flag_exponent
;
top
->
type
=
json_double
;
continue
;
}
}
else
if
(
b
==
'+'
||
b
==
'-'
)
{
if
(
flags
&
flag_exponent
&&
!
(
flags
&
flag_got_exponent_sign
))
{
flags
|=
flag_got_exponent_sign
;
continue
;
}
}
else
if
(
b
==
'.'
&&
top
->
type
==
json_integer
)
{
top
->
type
=
json_double
;
continue
;
}
flags
|=
flag_next
|
flag_reproc
;
break
;
default:
break
;
};
}
if
(
flags
&
flag_reproc
)
{
flags
&=
~
flag_reproc
;
--
i
;
}
if
(
flags
&
flag_next
)
{
flags
=
(
flags
&
~
flag_next
)
|
flag_need_comma
;
if
(
!
top
->
parent
)
{
/* root value done */
flags
|=
flag_done
;
continue
;
}
if
(
top
->
parent
->
type
==
json_array
)
flags
|=
flag_seek_value
;
if
(
!
state
.
first_pass
)
{
json_value
*
parent
=
top
->
parent
;
switch
(
parent
->
type
)
{
case
json_object
:
parent
->
u
.
object
.
values
[
parent
->
u
.
object
.
length
].
value
=
top
;
break
;
case
json_array
:
parent
->
u
.
array
.
values
[
parent
->
u
.
array
.
length
]
=
top
;
break
;
default:
break
;
};
}
if
(
(
++
top
->
parent
->
u
.
array
.
length
)
>
state
.
uint_max
)
goto
e_overflow
;
top
=
top
->
parent
;
continue
;
}
}
alloc
=
root
;
}
return
root
;
e_unknown_value:
sprintf
(
error
,
"%d:%d: Unknown value"
,
cur_line
,
e_off
);
goto
e_failed
;
e_alloc_failure:
strcpy
(
error
,
"Memory allocation failure"
);
goto
e_failed
;
e_overflow:
sprintf
(
error
,
"%d:%d: Too long (caught overflow)"
,
cur_line
,
e_off
);
goto
e_failed
;
e_failed:
if
(
error_buf
)
{
if
(
*
error
)
strcpy
(
error_buf
,
error
);
else
strcpy
(
error_buf
,
"Unknown error"
);
}
if
(
state
.
first_pass
)
alloc
=
root
;
while
(
alloc
)
{
top
=
alloc
->
_reserved
.
next_alloc
;
free
(
alloc
);
alloc
=
top
;
}
if
(
!
state
.
first_pass
)
json_value_free
(
root
);
return
0
;
}
json_value
*
json_parse
(
const
json_char
*
json
)
{
json_settings
settings
;
memset
(
&
settings
,
0
,
sizeof
(
json_settings
));
return
json_parse_ex
(
&
settings
,
json
,
0
);
}
void
json_value_free
(
json_value
*
value
)
{
json_value
*
cur_value
;
if
(
!
value
)
return
;
value
->
parent
=
0
;
while
(
value
)
{
switch
(
value
->
type
)
{
case
json_array
:
if
(
!
value
->
u
.
array
.
length
)
{
free
(
value
->
u
.
array
.
values
);
break
;
}
value
=
value
->
u
.
array
.
values
[
--
value
->
u
.
array
.
length
];
continue
;
case
json_object
:
if
(
!
value
->
u
.
object
.
length
)
{
free
(
value
->
u
.
object
.
values
);
break
;
}
value
=
value
->
u
.
object
.
values
[
--
value
->
u
.
object
.
length
].
value
;
continue
;
case
json_string
:
free
(
value
->
u
.
string
.
ptr
);
break
;
default:
break
;
};
cur_value
=
value
;
value
=
value
->
parent
;
free
(
cur_value
);
}
}
modules/misc/webservices/json.h
0 → 100644
View file @
0248a7fc
/*****************************************************************************
* json.h: json-parser fixups
*****************************************************************************
* Copyright (C) 2012 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef _JSON_H
#ifndef _JSONFIXUPS_H
#define _JSONFIXUPS_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_charset.h>
/* json.c depends on the locale */
#define strtod(foo,bar) us_strtod(foo,bar)
#include "use_json.h"
#endif
#endif
modules/misc/webservices/use_json.h
0 → 100644
View file @
0248a7fc
/* vim: set et ts=3 sw=3 ft=c:
*
* Copyright (C) 2012 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#ifndef _JSON_H
#define _JSON_H
#ifndef json_char
#define json_char char
#endif
#ifdef __cplusplus
#include <string.h>
extern
"C"
{
#endif
typedef
struct
{
unsigned
long
max_memory
;
int
settings
;
}
json_settings
;
#define json_relaxed_commas 1
typedef
enum
{
json_none
,
json_object
,
json_array
,
json_integer
,
json_double
,
json_string
,
json_boolean
,
json_null
}
json_type
;
extern
const
struct
_json_value
json_value_none
;
typedef
struct
_json_value
{
struct
_json_value
*
parent
;
json_type
type
;
union
{
int
boolean
;
long
integer
;
double
dbl
;
struct
{
unsigned
int
length
;
json_char
*
ptr
;
/* null terminated */
}
string
;
struct
{
unsigned
int
length
;
struct
{
json_char
*
name
;
struct
_json_value
*
value
;
}
*
values
;
}
object
;
struct
{
unsigned
int
length
;
struct
_json_value
**
values
;
}
array
;
}
u
;
union
{
struct
_json_value
*
next_alloc
;
void
*
object_mem
;
}
_reserved
;
/* Some C++ operator sugar */
#ifdef __cplusplus
public:
inline
_json_value
()
{
memset
(
this
,
0
,
sizeof
(
_json_value
));
}
inline
const
struct
_json_value
&
operator
[]
(
int
index
)
const
{
if
(
type
!=
json_array
||
index
<
0
||
((
unsigned
int
)
index
)
>=
u
.
array
.
length
)
{
return
json_value_none
;
}
return
*
u
.
array
.
values
[
index
];
}
inline
const
struct
_json_value
&
operator
[]
(
const
char
*
index
)
const
{
if
(
type
!=
json_object
)
return
json_value_none
;
for
(
unsigned
int
i
=
0
;
i
<
u
.
object
.
length
;
++
i
)
if
(
!
strcmp
(
u
.
object
.
values
[
i
].
name
,
index
))
return
*
u
.
object
.
values
[
i
].
value
;
return
json_value_none
;
}
inline
operator
const
char
*
()
const
{
switch
(
type
)
{
case
json_string
:
return
u
.
string
.
ptr
;
default:
return
""
;
};
}
inline
operator
long
()
const
{
return
u
.
integer
;
}
inline
operator
bool
()
const
{
return
u
.
boolean
!=
0
;
}
#endif
}
json_value
;
json_value
*
json_parse
(
const
json_char
*
json
);
json_value
*
json_parse_ex
(
json_settings
*
settings
,
const
json_char
*
json
,
char
*
error
);
void
json_value_free
(
json_value
*
);
#ifdef __cplusplus
}
/* extern "C" */
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment