Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
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
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$
* fb: video output module for the Linux framebuffer
* fdkaac: AAC encoder using the fdk-aac library
* filesystem: Filesystem access module
* fingerprinter: AcoustID audio fingerprinter using chromaprint
* flac: Flac decoder using libflac
* flacsys: FLAC demuxer
* float_mixer: Precise float audio mixer
...
...
modules/misc/Modules.am
View file @
0248a7fc
SOURCES_vod_rtsp = rtsp.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
libexport_plugin_la_SOURCES = \
...
...
@@ -48,6 +54,7 @@ libstats_plugin_la_LIBADD = $(AM_LIBADD)
libvlc_LTLIBRARIES += \
libaudioscrobbler_plugin.la \
libfingerprinter_plugin.la \
liblogger_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